OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 package org.webrtc.voiceengine; | 11 package org.webrtc.voiceengine; |
12 | 12 |
13 import android.annotation.TargetApi; | 13 import android.annotation.TargetApi; |
14 import android.content.Context; | 14 import android.content.Context; |
15 import android.media.AudioFormat; | 15 import android.media.AudioFormat; |
16 import android.media.AudioRecord; | 16 import android.media.AudioRecord; |
17 import android.media.MediaRecorder.AudioSource; | 17 import android.media.MediaRecorder.AudioSource; |
18 import android.os.Process; | 18 import android.os.Process; |
19 import java.lang.System; | 19 import java.lang.System; |
20 import java.nio.ByteBuffer; | 20 import java.nio.ByteBuffer; |
21 import java.util.concurrent.TimeUnit; | 21 import java.util.concurrent.TimeUnit; |
| 22 import org.webrtc.ContextUtils; |
22 import org.webrtc.Logging; | 23 import org.webrtc.Logging; |
23 import org.webrtc.ThreadUtils; | 24 import org.webrtc.ThreadUtils; |
24 | 25 |
25 public class WebRtcAudioRecord { | 26 public class WebRtcAudioRecord { |
26 private static final boolean DEBUG = false; | 27 private static final boolean DEBUG = false; |
27 | 28 |
28 private static final String TAG = "WebRtcAudioRecord"; | 29 private static final String TAG = "WebRtcAudioRecord"; |
29 | 30 |
30 // Default audio data format is PCM 16 bit per sample. | 31 // Default audio data format is PCM 16 bit per sample. |
31 // Guaranteed to be supported by all devices. | 32 // Guaranteed to be supported by all devices. |
32 private static final int BITS_PER_SAMPLE = 16; | 33 private static final int BITS_PER_SAMPLE = 16; |
33 | 34 |
34 // Requested size of each recorded buffer provided to the client. | 35 // Requested size of each recorded buffer provided to the client. |
35 private static final int CALLBACK_BUFFER_SIZE_MS = 10; | 36 private static final int CALLBACK_BUFFER_SIZE_MS = 10; |
36 | 37 |
37 // Average number of callbacks per second. | 38 // Average number of callbacks per second. |
38 private static final int BUFFERS_PER_SECOND = 1000 / CALLBACK_BUFFER_SIZE_MS; | 39 private static final int BUFFERS_PER_SECOND = 1000 / CALLBACK_BUFFER_SIZE_MS; |
39 | 40 |
40 // We ask for a native buffer size of BUFFER_SIZE_FACTOR * (minimum required | 41 // We ask for a native buffer size of BUFFER_SIZE_FACTOR * (minimum required |
41 // buffer size). The extra space is allocated to guard against glitches under | 42 // buffer size). The extra space is allocated to guard against glitches under |
42 // high load. | 43 // high load. |
43 private static final int BUFFER_SIZE_FACTOR = 2; | 44 private static final int BUFFER_SIZE_FACTOR = 2; |
44 | 45 |
45 // The AudioRecordJavaThread is allowed to wait for successful call to join() | 46 // The AudioRecordJavaThread is allowed to wait for successful call to join() |
46 // but the wait times out afther this amount of time. | 47 // but the wait times out afther this amount of time. |
47 private static final long AUDIO_RECORD_THREAD_JOIN_TIMEOUT_MS = 2000; | 48 private static final long AUDIO_RECORD_THREAD_JOIN_TIMEOUT_MS = 2000; |
48 | 49 |
49 private final long nativeAudioRecord; | 50 private final long nativeAudioRecord; |
50 private final Context context; | |
51 | 51 |
52 private WebRtcAudioEffects effects = null; | 52 private WebRtcAudioEffects effects = null; |
53 | 53 |
54 private ByteBuffer byteBuffer; | 54 private ByteBuffer byteBuffer; |
55 | 55 |
56 private AudioRecord audioRecord = null; | 56 private AudioRecord audioRecord = null; |
57 private AudioRecordThread audioThread = null; | 57 private AudioRecordThread audioThread = null; |
58 | 58 |
59 private static volatile boolean microphoneMute = false; | 59 private static volatile boolean microphoneMute = false; |
60 private byte[] emptyBytes; | 60 private byte[] emptyBytes; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 } | 132 } |
133 | 133 |
134 // Stops the inner thread loop and also calls AudioRecord.stop(). | 134 // Stops the inner thread loop and also calls AudioRecord.stop(). |
135 // Does not block the calling thread. | 135 // Does not block the calling thread. |
136 public void stopThread() { | 136 public void stopThread() { |
137 Logging.d(TAG, "stopThread"); | 137 Logging.d(TAG, "stopThread"); |
138 keepAlive = false; | 138 keepAlive = false; |
139 } | 139 } |
140 } | 140 } |
141 | 141 |
142 WebRtcAudioRecord(Context context, long nativeAudioRecord) { | 142 WebRtcAudioRecord(long nativeAudioRecord) { |
143 Logging.d(TAG, "ctor" + WebRtcAudioUtils.getThreadInfo()); | 143 Logging.d(TAG, "ctor" + WebRtcAudioUtils.getThreadInfo()); |
144 this.context = context; | |
145 this.nativeAudioRecord = nativeAudioRecord; | 144 this.nativeAudioRecord = nativeAudioRecord; |
146 if (DEBUG) { | 145 if (DEBUG) { |
147 WebRtcAudioUtils.logDeviceInfo(TAG); | 146 WebRtcAudioUtils.logDeviceInfo(TAG); |
148 } | 147 } |
149 effects = WebRtcAudioEffects.create(); | 148 effects = WebRtcAudioEffects.create(); |
150 } | 149 } |
151 | 150 |
152 private boolean enableBuiltInAEC(boolean enable) { | 151 private boolean enableBuiltInAEC(boolean enable) { |
153 Logging.d(TAG, "enableBuiltInAEC(" + enable + ')'); | 152 Logging.d(TAG, "enableBuiltInAEC(" + enable + ')'); |
154 if (effects == null) { | 153 if (effects == null) { |
155 Logging.e(TAG, "Built-in AEC is not supported on this platform"); | 154 Logging.e(TAG, "Built-in AEC is not supported on this platform"); |
156 return false; | 155 return false; |
157 } | 156 } |
158 return effects.setAEC(enable); | 157 return effects.setAEC(enable); |
159 } | 158 } |
160 | 159 |
161 private boolean enableBuiltInNS(boolean enable) { | 160 private boolean enableBuiltInNS(boolean enable) { |
162 Logging.d(TAG, "enableBuiltInNS(" + enable + ')'); | 161 Logging.d(TAG, "enableBuiltInNS(" + enable + ')'); |
163 if (effects == null) { | 162 if (effects == null) { |
164 Logging.e(TAG, "Built-in NS is not supported on this platform"); | 163 Logging.e(TAG, "Built-in NS is not supported on this platform"); |
165 return false; | 164 return false; |
166 } | 165 } |
167 return effects.setNS(enable); | 166 return effects.setNS(enable); |
168 } | 167 } |
169 | 168 |
170 private int initRecording(int sampleRate, int channels) { | 169 private int initRecording(int sampleRate, int channels) { |
171 Logging.d(TAG, "initRecording(sampleRate=" + sampleRate + ", channels=" + ch
annels + ")"); | 170 Logging.d(TAG, "initRecording(sampleRate=" + sampleRate + ", channels=" + ch
annels + ")"); |
172 if (!WebRtcAudioUtils.hasPermission(context, android.Manifest.permission.REC
ORD_AUDIO)) { | 171 if (!WebRtcAudioUtils.hasPermission( |
| 172 ContextUtils.getApplicationContext(), android.Manifest.permission.RE
CORD_AUDIO)) { |
173 reportWebRtcAudioRecordInitError("RECORD_AUDIO permission is missing"); | 173 reportWebRtcAudioRecordInitError("RECORD_AUDIO permission is missing"); |
174 return -1; | 174 return -1; |
175 } | 175 } |
176 if (audioRecord != null) { | 176 if (audioRecord != null) { |
177 reportWebRtcAudioRecordInitError("InitRecording called twice without StopR
ecording."); | 177 reportWebRtcAudioRecordInitError("InitRecording called twice without StopR
ecording."); |
178 return -1; | 178 return -1; |
179 } | 179 } |
180 final int bytesPerFrame = channels * (BITS_PER_SAMPLE / 8); | 180 final int bytesPerFrame = channels * (BITS_PER_SAMPLE / 8); |
181 final int framesPerBuffer = sampleRate / BUFFERS_PER_SECOND; | 181 final int framesPerBuffer = sampleRate / BUFFERS_PER_SECOND; |
182 byteBuffer = ByteBuffer.allocateDirect(bytesPerFrame * framesPerBuffer); | 182 byteBuffer = ByteBuffer.allocateDirect(bytesPerFrame * framesPerBuffer); |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 } | 324 } |
325 } | 325 } |
326 | 326 |
327 private void reportWebRtcAudioRecordError(String errorMessage) { | 327 private void reportWebRtcAudioRecordError(String errorMessage) { |
328 Logging.e(TAG, "Run-time recording error: " + errorMessage); | 328 Logging.e(TAG, "Run-time recording error: " + errorMessage); |
329 if (errorCallback != null) { | 329 if (errorCallback != null) { |
330 errorCallback.onWebRtcAudioRecordError(errorMessage); | 330 errorCallback.onWebRtcAudioRecordError(errorMessage); |
331 } | 331 } |
332 } | 332 } |
333 } | 333 } |
OLD | NEW |