• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2018 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/aaudio_recorder.h"
12 
13 #include <memory>
14 
15 #include "api/array_view.h"
16 #include "api/task_queue/task_queue_base.h"
17 #include "modules/audio_device/android/audio_manager.h"
18 #include "modules/audio_device/fine_audio_buffer.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21 #include "rtc_base/time_utils.h"
22 
23 namespace webrtc {
24 
AAudioRecorder(AudioManager * audio_manager)25 AAudioRecorder::AAudioRecorder(AudioManager* audio_manager)
26     : main_thread_(TaskQueueBase::Current()),
27       aaudio_(audio_manager, AAUDIO_DIRECTION_INPUT, this) {
28   RTC_LOG(LS_INFO) << "ctor";
29   thread_checker_aaudio_.Detach();
30 }
31 
~AAudioRecorder()32 AAudioRecorder::~AAudioRecorder() {
33   RTC_LOG(LS_INFO) << "dtor";
34   RTC_DCHECK(thread_checker_.IsCurrent());
35   Terminate();
36   RTC_LOG(LS_INFO) << "detected owerflows: " << overflow_count_;
37 }
38 
Init()39 int AAudioRecorder::Init() {
40   RTC_LOG(LS_INFO) << "Init";
41   RTC_DCHECK(thread_checker_.IsCurrent());
42   if (aaudio_.audio_parameters().channels() == 2) {
43     RTC_DLOG(LS_WARNING) << "Stereo mode is enabled";
44   }
45   return 0;
46 }
47 
Terminate()48 int AAudioRecorder::Terminate() {
49   RTC_LOG(LS_INFO) << "Terminate";
50   RTC_DCHECK(thread_checker_.IsCurrent());
51   StopRecording();
52   return 0;
53 }
54 
InitRecording()55 int AAudioRecorder::InitRecording() {
56   RTC_LOG(LS_INFO) << "InitRecording";
57   RTC_DCHECK(thread_checker_.IsCurrent());
58   RTC_DCHECK(!initialized_);
59   RTC_DCHECK(!recording_);
60   if (!aaudio_.Init()) {
61     return -1;
62   }
63   initialized_ = true;
64   return 0;
65 }
66 
StartRecording()67 int AAudioRecorder::StartRecording() {
68   RTC_LOG(LS_INFO) << "StartRecording";
69   RTC_DCHECK(thread_checker_.IsCurrent());
70   RTC_DCHECK(initialized_);
71   RTC_DCHECK(!recording_);
72   if (fine_audio_buffer_) {
73     fine_audio_buffer_->ResetPlayout();
74   }
75   if (!aaudio_.Start()) {
76     return -1;
77   }
78   overflow_count_ = aaudio_.xrun_count();
79   first_data_callback_ = true;
80   recording_ = true;
81   return 0;
82 }
83 
StopRecording()84 int AAudioRecorder::StopRecording() {
85   RTC_LOG(LS_INFO) << "StopRecording";
86   RTC_DCHECK(thread_checker_.IsCurrent());
87   if (!initialized_ || !recording_) {
88     return 0;
89   }
90   if (!aaudio_.Stop()) {
91     return -1;
92   }
93   thread_checker_aaudio_.Detach();
94   initialized_ = false;
95   recording_ = false;
96   return 0;
97 }
98 
AttachAudioBuffer(AudioDeviceBuffer * audioBuffer)99 void AAudioRecorder::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
100   RTC_LOG(LS_INFO) << "AttachAudioBuffer";
101   RTC_DCHECK(thread_checker_.IsCurrent());
102   audio_device_buffer_ = audioBuffer;
103   const AudioParameters audio_parameters = aaudio_.audio_parameters();
104   audio_device_buffer_->SetRecordingSampleRate(audio_parameters.sample_rate());
105   audio_device_buffer_->SetRecordingChannels(audio_parameters.channels());
106   RTC_CHECK(audio_device_buffer_);
107   // Create a modified audio buffer class which allows us to deliver any number
108   // of samples (and not only multiples of 10ms which WebRTC uses) to match the
109   // native AAudio buffer size.
110   fine_audio_buffer_ = std::make_unique<FineAudioBuffer>(audio_device_buffer_);
111 }
112 
EnableBuiltInAEC(bool enable)113 int AAudioRecorder::EnableBuiltInAEC(bool enable) {
114   RTC_LOG(LS_INFO) << "EnableBuiltInAEC: " << enable;
115   RTC_LOG(LS_ERROR) << "Not implemented";
116   return -1;
117 }
118 
EnableBuiltInAGC(bool enable)119 int AAudioRecorder::EnableBuiltInAGC(bool enable) {
120   RTC_LOG(LS_INFO) << "EnableBuiltInAGC: " << enable;
121   RTC_LOG(LS_ERROR) << "Not implemented";
122   return -1;
123 }
124 
EnableBuiltInNS(bool enable)125 int AAudioRecorder::EnableBuiltInNS(bool enable) {
126   RTC_LOG(LS_INFO) << "EnableBuiltInNS: " << enable;
127   RTC_LOG(LS_ERROR) << "Not implemented";
128   return -1;
129 }
130 
OnErrorCallback(aaudio_result_t error)131 void AAudioRecorder::OnErrorCallback(aaudio_result_t error) {
132   RTC_LOG(LS_ERROR) << "OnErrorCallback: " << AAudio_convertResultToText(error);
133   // RTC_DCHECK(thread_checker_aaudio_.IsCurrent());
134   if (aaudio_.stream_state() == AAUDIO_STREAM_STATE_DISCONNECTED) {
135     // The stream is disconnected and any attempt to use it will return
136     // AAUDIO_ERROR_DISCONNECTED..
137     RTC_LOG(LS_WARNING) << "Input stream disconnected => restart is required";
138     // AAudio documentation states: "You should not close or reopen the stream
139     // from the callback, use another thread instead". A message is therefore
140     // sent to the main thread to do the restart operation.
141     RTC_DCHECK(main_thread_);
142     main_thread_->PostTask([this] { HandleStreamDisconnected(); });
143   }
144 }
145 
146 // Read and process `num_frames` of data from the `audio_data` buffer.
147 // TODO(henrika): possibly add trace here to be included in systrace.
148 // See https://developer.android.com/studio/profile/systrace-commandline.html.
OnDataCallback(void * audio_data,int32_t num_frames)149 aaudio_data_callback_result_t AAudioRecorder::OnDataCallback(
150     void* audio_data,
151     int32_t num_frames) {
152   // TODO(henrika): figure out why we sometimes hit this one.
153   // RTC_DCHECK(thread_checker_aaudio_.IsCurrent());
154   // RTC_LOG(LS_INFO) << "OnDataCallback: " << num_frames;
155   // Drain the input buffer at first callback to ensure that it does not
156   // contain any old data. Will also ensure that the lowest possible latency
157   // is obtained.
158   if (first_data_callback_) {
159     RTC_LOG(LS_INFO) << "--- First input data callback: "
160                         "device id="
161                      << aaudio_.device_id();
162     aaudio_.ClearInputStream(audio_data, num_frames);
163     first_data_callback_ = false;
164   }
165   // Check if the overflow counter has increased and if so log a warning.
166   // TODO(henrika): possible add UMA stat or capacity extension.
167   const int32_t overflow_count = aaudio_.xrun_count();
168   if (overflow_count > overflow_count_) {
169     RTC_LOG(LS_ERROR) << "Overflow detected: " << overflow_count;
170     overflow_count_ = overflow_count;
171   }
172   // Estimated time between an audio frame was recorded by the input device and
173   // it can read on the input stream.
174   latency_millis_ = aaudio_.EstimateLatencyMillis();
175   // TODO(henrika): use for development only.
176   if (aaudio_.frames_read() % (1000 * aaudio_.frames_per_burst()) == 0) {
177     RTC_DLOG(LS_INFO) << "input latency: " << latency_millis_
178                       << ", num_frames: " << num_frames;
179   }
180   // Copy recorded audio in `audio_data` to the WebRTC sink using the
181   // FineAudioBuffer object.
182   fine_audio_buffer_->DeliverRecordedData(
183       rtc::MakeArrayView(static_cast<const int16_t*>(audio_data),
184                          aaudio_.samples_per_frame() * num_frames),
185       static_cast<int>(latency_millis_ + 0.5));
186 
187   return AAUDIO_CALLBACK_RESULT_CONTINUE;
188 }
189 
HandleStreamDisconnected()190 void AAudioRecorder::HandleStreamDisconnected() {
191   RTC_DCHECK_RUN_ON(&thread_checker_);
192   RTC_LOG(LS_INFO) << "HandleStreamDisconnected";
193   if (!initialized_ || !recording_) {
194     return;
195   }
196   // Perform a restart by first closing the disconnected stream and then start
197   // a new stream; this time using the new (preferred) audio input device.
198   // TODO(henrika): resolve issue where a one restart attempt leads to a long
199   // sequence of new calls to OnErrorCallback().
200   // See b/73148976 for details.
201   StopRecording();
202   InitRecording();
203   StartRecording();
204 }
205 }  // namespace webrtc
206