Home | History | Annotate | Download | only in android
      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.
     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 
     43 AudioRecordJni::JavaAudioRecord::~JavaAudioRecord() {}
     44 
     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 
     52 bool AudioRecordJni::JavaAudioRecord::StartRecording() {
     53   return audio_record_->CallBooleanMethod(start_recording_);
     54 }
     55 
     56 bool AudioRecordJni::JavaAudioRecord::StopRecording() {
     57   return audio_record_->CallBooleanMethod(stop_recording_);
     58 }
     59 
     60 bool AudioRecordJni::JavaAudioRecord::EnableBuiltInAEC(bool enable) {
     61   return audio_record_->CallBooleanMethod(enable_built_in_aec_,
     62                                           static_cast<jboolean>(enable));
     63 }
     64 
     65 bool AudioRecordJni::JavaAudioRecord::EnableBuiltInAGC(bool enable) {
     66   return audio_record_->CallBooleanMethod(enable_built_in_agc_,
     67                                           static_cast<jboolean>(enable));
     68 }
     69 
     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.
     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 
    109 AudioRecordJni::~AudioRecordJni() {
    110   ALOGD("~dtor%s", GetThreadInfo().c_str());
    111   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    112   Terminate();
    113 }
    114 
    115 int32_t AudioRecordJni::Init() {
    116   ALOGD("Init%s", GetThreadInfo().c_str());
    117   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    118   return 0;
    119 }
    120 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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'.
    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