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