• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "webrtc/modules/audio_device/android/audio_record_jni.h"
12 
13 #include <utility>
14 
15 #include <android/log.h>
16 
17 #include "webrtc/base/arraysize.h"
18 #include "webrtc/base/checks.h"
19 #include "webrtc/base/format_macros.h"
20 #include "webrtc/modules/audio_device/android/audio_common.h"
21 
22 #define TAG "AudioRecordJni"
23 #define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
24 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
25 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
26 #define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
27 #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
28 
29 namespace webrtc {
30 
31 // AudioRecordJni::JavaAudioRecord implementation.
JavaAudioRecord(NativeRegistration * native_reg,rtc::scoped_ptr<GlobalRef> audio_record)32 AudioRecordJni::JavaAudioRecord::JavaAudioRecord(
33     NativeRegistration* native_reg,
34     rtc::scoped_ptr<GlobalRef> audio_record)
35     : audio_record_(std::move(audio_record)),
36       init_recording_(native_reg->GetMethodId("initRecording", "(II)I")),
37       start_recording_(native_reg->GetMethodId("startRecording", "()Z")),
38       stop_recording_(native_reg->GetMethodId("stopRecording", "()Z")),
39       enable_built_in_aec_(native_reg->GetMethodId("enableBuiltInAEC", "(Z)Z")),
40       enable_built_in_agc_(native_reg->GetMethodId("enableBuiltInAGC", "(Z)Z")),
41       enable_built_in_ns_(native_reg->GetMethodId("enableBuiltInNS", "(Z)Z")) {}
42 
~JavaAudioRecord()43 AudioRecordJni::JavaAudioRecord::~JavaAudioRecord() {}
44 
InitRecording(int sample_rate,size_t channels)45 int AudioRecordJni::JavaAudioRecord::InitRecording(
46     int sample_rate, size_t channels) {
47   return audio_record_->CallIntMethod(init_recording_,
48                                       static_cast<jint>(sample_rate),
49                                       static_cast<jint>(channels));
50 }
51 
StartRecording()52 bool AudioRecordJni::JavaAudioRecord::StartRecording() {
53   return audio_record_->CallBooleanMethod(start_recording_);
54 }
55 
StopRecording()56 bool AudioRecordJni::JavaAudioRecord::StopRecording() {
57   return audio_record_->CallBooleanMethod(stop_recording_);
58 }
59 
EnableBuiltInAEC(bool enable)60 bool AudioRecordJni::JavaAudioRecord::EnableBuiltInAEC(bool enable) {
61   return audio_record_->CallBooleanMethod(enable_built_in_aec_,
62                                           static_cast<jboolean>(enable));
63 }
64 
EnableBuiltInAGC(bool enable)65 bool AudioRecordJni::JavaAudioRecord::EnableBuiltInAGC(bool enable) {
66   return audio_record_->CallBooleanMethod(enable_built_in_agc_,
67                                           static_cast<jboolean>(enable));
68 }
69 
EnableBuiltInNS(bool enable)70 bool AudioRecordJni::JavaAudioRecord::EnableBuiltInNS(bool enable) {
71   return audio_record_->CallBooleanMethod(enable_built_in_ns_,
72                                           static_cast<jboolean>(enable));
73 }
74 
75 // AudioRecordJni implementation.
AudioRecordJni(AudioManager * audio_manager)76 AudioRecordJni::AudioRecordJni(AudioManager* audio_manager)
77     : j_environment_(JVM::GetInstance()->environment()),
78       audio_manager_(audio_manager),
79       audio_parameters_(audio_manager->GetRecordAudioParameters()),
80       total_delay_in_milliseconds_(0),
81       direct_buffer_address_(nullptr),
82       direct_buffer_capacity_in_bytes_(0),
83       frames_per_buffer_(0),
84       initialized_(false),
85       recording_(false),
86       audio_device_buffer_(nullptr) {
87   ALOGD("ctor%s", GetThreadInfo().c_str());
88   RTC_DCHECK(audio_parameters_.is_valid());
89   RTC_CHECK(j_environment_);
90   JNINativeMethod native_methods[] = {
91       {"nativeCacheDirectBufferAddress", "(Ljava/nio/ByteBuffer;J)V",
92       reinterpret_cast<void*>(
93           &webrtc::AudioRecordJni::CacheDirectBufferAddress)},
94       {"nativeDataIsRecorded", "(IJ)V",
95       reinterpret_cast<void*>(&webrtc::AudioRecordJni::DataIsRecorded)}};
96   j_native_registration_ = j_environment_->RegisterNatives(
97       "org/webrtc/voiceengine/WebRtcAudioRecord",
98       native_methods, arraysize(native_methods));
99   j_audio_record_.reset(new JavaAudioRecord(
100       j_native_registration_.get(),
101       j_native_registration_->NewObject(
102           "<init>", "(Landroid/content/Context;J)V",
103           JVM::GetInstance()->context(), PointerTojlong(this))));
104   // Detach from this thread since we want to use the checker to verify calls
105   // from the Java based audio thread.
106   thread_checker_java_.DetachFromThread();
107 }
108 
~AudioRecordJni()109 AudioRecordJni::~AudioRecordJni() {
110   ALOGD("~dtor%s", GetThreadInfo().c_str());
111   RTC_DCHECK(thread_checker_.CalledOnValidThread());
112   Terminate();
113 }
114 
Init()115 int32_t AudioRecordJni::Init() {
116   ALOGD("Init%s", GetThreadInfo().c_str());
117   RTC_DCHECK(thread_checker_.CalledOnValidThread());
118   return 0;
119 }
120 
Terminate()121 int32_t AudioRecordJni::Terminate() {
122   ALOGD("Terminate%s", GetThreadInfo().c_str());
123   RTC_DCHECK(thread_checker_.CalledOnValidThread());
124   StopRecording();
125   return 0;
126 }
127 
InitRecording()128 int32_t AudioRecordJni::InitRecording() {
129   ALOGD("InitRecording%s", GetThreadInfo().c_str());
130   RTC_DCHECK(thread_checker_.CalledOnValidThread());
131   RTC_DCHECK(!initialized_);
132   RTC_DCHECK(!recording_);
133   int frames_per_buffer = j_audio_record_->InitRecording(
134       audio_parameters_.sample_rate(), audio_parameters_.channels());
135   if (frames_per_buffer < 0) {
136     ALOGE("InitRecording failed!");
137     return -1;
138   }
139   frames_per_buffer_ = static_cast<size_t>(frames_per_buffer);
140   ALOGD("frames_per_buffer: %" PRIuS, frames_per_buffer_);
141   RTC_CHECK_EQ(direct_buffer_capacity_in_bytes_,
142                frames_per_buffer_ * kBytesPerFrame);
143   RTC_CHECK_EQ(frames_per_buffer_, audio_parameters_.frames_per_10ms_buffer());
144   initialized_ = true;
145   return 0;
146 }
147 
StartRecording()148 int32_t AudioRecordJni::StartRecording() {
149   ALOGD("StartRecording%s", GetThreadInfo().c_str());
150   RTC_DCHECK(thread_checker_.CalledOnValidThread());
151   RTC_DCHECK(initialized_);
152   RTC_DCHECK(!recording_);
153   if (!j_audio_record_->StartRecording()) {
154     ALOGE("StartRecording failed!");
155     return -1;
156   }
157   recording_ = true;
158   return 0;
159 }
160 
StopRecording()161 int32_t AudioRecordJni::StopRecording() {
162   ALOGD("StopRecording%s", GetThreadInfo().c_str());
163   RTC_DCHECK(thread_checker_.CalledOnValidThread());
164   if (!initialized_ || !recording_) {
165     return 0;
166   }
167   if (!j_audio_record_->StopRecording()) {
168     ALOGE("StopRecording failed!");
169     return -1;
170   }
171   // If we don't detach here, we will hit a RTC_DCHECK in OnDataIsRecorded()
172   // next time StartRecording() is called since it will create a new Java
173   // thread.
174   thread_checker_java_.DetachFromThread();
175   initialized_ = false;
176   recording_ = false;
177   direct_buffer_address_= nullptr;
178   return 0;
179 }
180 
AttachAudioBuffer(AudioDeviceBuffer * audioBuffer)181 void AudioRecordJni::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
182   ALOGD("AttachAudioBuffer");
183   RTC_DCHECK(thread_checker_.CalledOnValidThread());
184   audio_device_buffer_ = audioBuffer;
185   const int sample_rate_hz = audio_parameters_.sample_rate();
186   ALOGD("SetRecordingSampleRate(%d)", sample_rate_hz);
187   audio_device_buffer_->SetRecordingSampleRate(sample_rate_hz);
188   const size_t channels = audio_parameters_.channels();
189   ALOGD("SetRecordingChannels(%" PRIuS ")", channels);
190   audio_device_buffer_->SetRecordingChannels(channels);
191   total_delay_in_milliseconds_ =
192       audio_manager_->GetDelayEstimateInMilliseconds();
193   RTC_DCHECK_GT(total_delay_in_milliseconds_, 0);
194   ALOGD("total_delay_in_milliseconds: %d", total_delay_in_milliseconds_);
195 }
196 
EnableBuiltInAEC(bool enable)197 int32_t AudioRecordJni::EnableBuiltInAEC(bool enable) {
198   ALOGD("EnableBuiltInAEC%s", GetThreadInfo().c_str());
199   RTC_DCHECK(thread_checker_.CalledOnValidThread());
200   return j_audio_record_->EnableBuiltInAEC(enable) ? 0 : -1;
201 }
202 
EnableBuiltInAGC(bool enable)203 int32_t AudioRecordJni::EnableBuiltInAGC(bool enable) {
204   ALOGD("EnableBuiltInAGC%s", GetThreadInfo().c_str());
205   RTC_DCHECK(thread_checker_.CalledOnValidThread());
206   return j_audio_record_->EnableBuiltInAGC(enable) ? 0 : -1;
207 }
208 
EnableBuiltInNS(bool enable)209 int32_t AudioRecordJni::EnableBuiltInNS(bool enable) {
210   ALOGD("EnableBuiltInNS%s", GetThreadInfo().c_str());
211   RTC_DCHECK(thread_checker_.CalledOnValidThread());
212   return j_audio_record_->EnableBuiltInNS(enable) ? 0 : -1;
213 }
214 
CacheDirectBufferAddress(JNIEnv * env,jobject obj,jobject byte_buffer,jlong nativeAudioRecord)215 void JNICALL AudioRecordJni::CacheDirectBufferAddress(
216     JNIEnv* env, jobject obj, jobject byte_buffer, jlong nativeAudioRecord) {
217   webrtc::AudioRecordJni* this_object =
218       reinterpret_cast<webrtc::AudioRecordJni*> (nativeAudioRecord);
219   this_object->OnCacheDirectBufferAddress(env, byte_buffer);
220 }
221 
OnCacheDirectBufferAddress(JNIEnv * env,jobject byte_buffer)222 void AudioRecordJni::OnCacheDirectBufferAddress(
223     JNIEnv* env, jobject byte_buffer) {
224   ALOGD("OnCacheDirectBufferAddress");
225   RTC_DCHECK(thread_checker_.CalledOnValidThread());
226   RTC_DCHECK(!direct_buffer_address_);
227   direct_buffer_address_ =
228       env->GetDirectBufferAddress(byte_buffer);
229   jlong capacity = env->GetDirectBufferCapacity(byte_buffer);
230   ALOGD("direct buffer capacity: %lld", capacity);
231   direct_buffer_capacity_in_bytes_ = static_cast<size_t>(capacity);
232 }
233 
DataIsRecorded(JNIEnv * env,jobject obj,jint length,jlong nativeAudioRecord)234 void JNICALL AudioRecordJni::DataIsRecorded(
235   JNIEnv* env, jobject obj, jint length, jlong nativeAudioRecord) {
236   webrtc::AudioRecordJni* this_object =
237       reinterpret_cast<webrtc::AudioRecordJni*> (nativeAudioRecord);
238   this_object->OnDataIsRecorded(length);
239 }
240 
241 // This method is called on a high-priority thread from Java. The name of
242 // the thread is 'AudioRecordThread'.
OnDataIsRecorded(int length)243 void AudioRecordJni::OnDataIsRecorded(int length) {
244   RTC_DCHECK(thread_checker_java_.CalledOnValidThread());
245   if (!audio_device_buffer_) {
246     ALOGE("AttachAudioBuffer has not been called!");
247     return;
248   }
249   audio_device_buffer_->SetRecordedBuffer(direct_buffer_address_,
250                                           frames_per_buffer_);
251   // We provide one (combined) fixed delay estimate for the APM and use the
252   // |playDelayMs| parameter only. Components like the AEC only sees the sum
253   // of |playDelayMs| and |recDelayMs|, hence the distributions does not matter.
254   audio_device_buffer_->SetVQEData(total_delay_in_milliseconds_,
255                                    0,   // recDelayMs
256                                    0);  // clockDrift
257   if (audio_device_buffer_->DeliverRecordedData() == -1) {
258     ALOGE("AudioDeviceBuffer::DeliverRecordedData failed!");
259   }
260 }
261 
262 }  // namespace webrtc
263