dillon - branch off of chromium-67.0.3396.87 and apply 67.bad-dfly
[chromium-dfly.git] / content / renderer / media / stream / processed_local_audio_source.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/renderer/media/stream/processed_local_audio_source.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/logging.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/strings/stringprintf.h"
13 #include "content/renderer/media/audio_device_factory.h"
14 #include "content/renderer/media/stream/media_stream_audio_processor_options.h"
15 #include "content/renderer/media/stream/media_stream_constraints_util.h"
16 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
17 #include "content/renderer/media/webrtc/webrtc_audio_device_impl.h"
18 #include "content/renderer/media/webrtc_logging.h"
19 #include "content/renderer/render_frame_impl.h"
20 #include "media/base/channel_layout.h"
21 #include "media/base/sample_rates.h"
22 #include "third_party/webrtc/api/mediaconstraintsinterface.h"
23 #include "third_party/webrtc/media/base/mediachannel.h"
24
25 namespace content {
26
27 namespace {
28 // Used as an identifier for ProcessedLocalAudioSource::From().
29 void* const kProcessedLocalAudioSourceIdentifier =
30     const_cast<void**>(&kProcessedLocalAudioSourceIdentifier);
31 }  // namespace
32
33 ProcessedLocalAudioSource::ProcessedLocalAudioSource(
34     int consumer_render_frame_id,
35     const MediaStreamDevice& device,
36     bool hotword_enabled,
37     bool disable_local_echo,
38     const AudioProcessingProperties& audio_processing_properties,
39     const ConstraintsCallback& started_callback,
40     PeerConnectionDependencyFactory* factory)
41     : MediaStreamAudioSource(true /* is_local_source */,
42                              hotword_enabled,
43                              disable_local_echo),
44       consumer_render_frame_id_(consumer_render_frame_id),
45       pc_factory_(factory),
46       audio_processing_properties_(audio_processing_properties),
47       started_callback_(started_callback),
48       volume_(0),
49       allow_invalid_render_frame_id_for_testing_(false) {
50   DCHECK(pc_factory_);
51   DVLOG(1) << "ProcessedLocalAudioSource::ProcessedLocalAudioSource()";
52   SetDevice(device);
53 }
54
55 ProcessedLocalAudioSource::~ProcessedLocalAudioSource() {
56   DVLOG(1) << "ProcessedLocalAudioSource::~ProcessedLocalAudioSource()";
57   EnsureSourceIsStopped();
58 }
59
60 // static
61 ProcessedLocalAudioSource* ProcessedLocalAudioSource::From(
62     MediaStreamAudioSource* source) {
63   if (source &&
64       source->GetClassIdentifier() == kProcessedLocalAudioSourceIdentifier)
65     return static_cast<ProcessedLocalAudioSource*>(source);
66   return nullptr;
67 }
68
69 void* ProcessedLocalAudioSource::GetClassIdentifier() const {
70   return kProcessedLocalAudioSourceIdentifier;
71 }
72
73 bool ProcessedLocalAudioSource::EnsureSourceIsStarted() {
74   DCHECK(thread_checker_.CalledOnValidThread());
75
76   {
77     base::AutoLock auto_lock(source_lock_);
78     if (source_)
79       return true;
80   }
81
82   // Sanity-check that the consuming RenderFrame still exists. This is required
83   // to initialize the audio source.
84   if (!allow_invalid_render_frame_id_for_testing_ &&
85       !RenderFrameImpl::FromRoutingID(consumer_render_frame_id_)) {
86     WebRtcLogMessage("ProcessedLocalAudioSource::EnsureSourceIsStarted() fails "
87                      " because the render frame does not exist.");
88     return false;
89   }
90
91   WebRtcLogMessage(base::StringPrintf(
92       "ProcessedLocalAudioSource::EnsureSourceIsStarted. render_frame_id=%d"
93       ", channel_layout=%d, sample_rate=%d, buffer_size=%d"
94       ", session_id=%d, effects=%d. ",
95       consumer_render_frame_id_, device().input.channel_layout(),
96       device().input.sample_rate(), device().input.frames_per_buffer(),
97       device().session_id, device().input.effects()));
98
99   MediaStreamDevice modified_device(device());
100   bool device_is_modified = false;
101
102   // Disable HW echo cancellation if constraints explicitly specified no
103   // echo cancellation.
104   if (audio_processing_properties_.disable_hw_echo_cancellation &&
105       (device().input.effects() & media::AudioParameters::ECHO_CANCELLER)) {
106     modified_device.input.set_effects(modified_device.input.effects() &
107                                       ~media::AudioParameters::ECHO_CANCELLER);
108     device_is_modified = true;
109   } else if (audio_processing_properties_
110                  .enable_experimental_hw_echo_cancellation &&
111              (device().input.effects() &
112               media::AudioParameters::EXPERIMENTAL_ECHO_CANCELLER)) {
113     // Set the ECHO_CANCELLER effect, since that is what controls what's
114     // actually being used. The EXPERIMENTAL_ flag only indicates availability.
115     modified_device.input.set_effects(modified_device.input.effects() |
116                                       media::AudioParameters::ECHO_CANCELLER);
117     device_is_modified = true;
118   }
119
120   // Disable noise suppression on the device if the properties explicitly
121   // specify to do so.
122   if (audio_processing_properties_.disable_hw_noise_suppression &&
123       (device().input.effects() & media::AudioParameters::NOISE_SUPPRESSION)) {
124     modified_device.input.set_effects(
125         modified_device.input.effects() &
126         ~media::AudioParameters::NOISE_SUPPRESSION);
127     device_is_modified = true;
128   }
129
130   if (device_is_modified)
131     SetDevice(modified_device);
132
133   // Create the MediaStreamAudioProcessor, bound to the WebRTC audio device
134   // module.
135   WebRtcAudioDeviceImpl* const rtc_audio_device =
136       pc_factory_->GetWebRtcAudioDevice();
137   if (!rtc_audio_device) {
138     WebRtcLogMessage("ProcessedLocalAudioSource::EnsureSourceIsStarted() fails "
139                      " because there is no WebRtcAudioDeviceImpl instance.");
140     return false;
141   }
142   audio_processor_ = new rtc::RefCountedObject<MediaStreamAudioProcessor>(
143       audio_processing_properties_, rtc_audio_device);
144
145   // If KEYBOARD_MIC effect is set, change the layout to the corresponding
146   // layout that includes the keyboard mic.
147   media::ChannelLayout channel_layout = device().input.channel_layout();
148   if ((device().input.effects() & media::AudioParameters::KEYBOARD_MIC) &&
149       audio_processing_properties_.goog_experimental_noise_suppression) {
150     if (channel_layout == media::CHANNEL_LAYOUT_STEREO) {
151       channel_layout = media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC;
152       DVLOG(1) << "Changed stereo layout to stereo + keyboard mic layout due "
153                << "to KEYBOARD_MIC effect.";
154     } else {
155       DVLOG(1) << "KEYBOARD_MIC effect ignored, not compatible with layout "
156                << channel_layout;
157     }
158   }
159
160   DVLOG(1) << "Audio input hardware channel layout: " << channel_layout;
161   UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout",
162                             channel_layout, media::CHANNEL_LAYOUT_MAX + 1);
163
164   // Verify that the reported input channel configuration is supported.
165   if (channel_layout != media::CHANNEL_LAYOUT_MONO &&
166       channel_layout != media::CHANNEL_LAYOUT_STEREO &&
167       channel_layout != media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
168     WebRtcLogMessage(base::StringPrintf(
169         "ProcessedLocalAudioSource::EnsureSourceIsStarted() fails "
170         " because the input channel layout (%d) is not supported.",
171         static_cast<int>(channel_layout)));
172     return false;
173   }
174
175   DVLOG(1) << "Audio input hardware sample rate: "
176            << device().input.sample_rate();
177   media::AudioSampleRate asr;
178   if (media::ToAudioSampleRate(device().input.sample_rate(), &asr)) {
179     UMA_HISTOGRAM_ENUMERATION(
180         "WebRTC.AudioInputSampleRate", asr, media::kAudioSampleRateMax + 1);
181   } else {
182     UMA_HISTOGRAM_COUNTS("WebRTC.AudioInputSampleRateUnexpected",
183                          device().input.sample_rate());
184   }
185
186   // Determine the audio format required of the AudioCapturerSource. Then, pass
187   // that to the |audio_processor_| and set the output format of this
188   // ProcessedLocalAudioSource to the processor's output format.
189   media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
190                                 channel_layout, device().input.sample_rate(),
191                                 16,
192                                 GetBufferSize(device().input.sample_rate()));
193   params.set_effects(device().input.effects());
194   DCHECK(params.IsValid());
195   audio_processor_->OnCaptureFormatChanged(params);
196   SetFormat(audio_processor_->OutputFormat());
197
198   // Start the source.
199   VLOG(1) << "Starting WebRTC audio source for consumption by render frame "
200           << consumer_render_frame_id_ << " with input parameters={"
201           << params.AsHumanReadableString() << "} and output parameters={"
202           << GetAudioParameters().AsHumanReadableString() << '}';
203   scoped_refptr<media::AudioCapturerSource> new_source =
204       AudioDeviceFactory::NewAudioCapturerSource(consumer_render_frame_id_);
205   new_source->Initialize(params, this, device().session_id);
206   // We need to set the AGC control before starting the stream.
207   new_source->SetAutomaticGainControl(true);
208   {
209     base::AutoLock auto_lock(source_lock_);
210     source_ = std::move(new_source);
211   }
212   source_->Start();
213
214   // Register this source with the WebRtcAudioDeviceImpl.
215   rtc_audio_device->AddAudioCapturer(this);
216
217   return true;
218 }
219
220 void ProcessedLocalAudioSource::EnsureSourceIsStopped() {
221   DCHECK(thread_checker_.CalledOnValidThread());
222
223   scoped_refptr<media::AudioCapturerSource> source_to_stop;
224   {
225     base::AutoLock auto_lock(source_lock_);
226     if (!source_)
227       return;
228     source_to_stop = std::move(source_);
229   }
230
231   if (WebRtcAudioDeviceImpl* rtc_audio_device =
232       pc_factory_->GetWebRtcAudioDevice()) {
233     rtc_audio_device->RemoveAudioCapturer(this);
234   }
235
236   source_to_stop->Stop();
237
238   // Stop the audio processor to avoid feeding render data into the processor.
239   audio_processor_->Stop();
240
241   VLOG(1) << "Stopped WebRTC audio pipeline for consumption by render frame "
242           << consumer_render_frame_id_ << '.';
243 }
244
245 void ProcessedLocalAudioSource::SetVolume(int volume) {
246   DVLOG(1) << "ProcessedLocalAudioSource::SetVolume()";
247   DCHECK_LE(volume, MaxVolume());
248
249   const double normalized_volume = static_cast<double>(volume) / MaxVolume();
250
251   // Hold a strong reference to |source_| while its SetVolume() method is
252   // called. This will prevent the object from being destroyed on another thread
253   // in the meantime. It's possible the |source_| will be stopped on another
254   // thread while calling SetVolume() here; but this is safe: The operation will
255   // simply be ignored.
256   scoped_refptr<media::AudioCapturerSource> maybe_source;
257   {
258     base::AutoLock auto_lock(source_lock_);
259     maybe_source = source_;
260   }
261   if (maybe_source)
262     maybe_source->SetVolume(normalized_volume);
263 }
264
265 int ProcessedLocalAudioSource::Volume() const {
266   // Note: Using NoBarrier_Load() because the timing of visibility of the
267   // updated volume information on other threads can be relaxed.
268   return base::subtle::NoBarrier_Load(&volume_);
269 }
270
271 int ProcessedLocalAudioSource::MaxVolume() const {
272   return WebRtcAudioDeviceImpl::kMaxVolumeLevel;
273 }
274
275 void ProcessedLocalAudioSource::OnCaptureStarted() {
276   started_callback_.Run(this, MEDIA_DEVICE_OK, "");
277 }
278
279 void ProcessedLocalAudioSource::Capture(const media::AudioBus* audio_bus,
280                                         int audio_delay_milliseconds,
281                                         double volume,
282                                         bool key_pressed) {
283 #if defined(OS_WIN) || defined(OS_MACOSX)
284   DCHECK_LE(volume, 1.0);
285 #elif (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_BSD)
286   // We have a special situation on Linux where the microphone volume can be
287   // "higher than maximum". The input volume slider in the sound preference
288   // allows the user to set a scaling that is higher than 100%. It means that
289   // even if the reported maximum levels is N, the actual microphone level can
290   // go up to 1.5x*N and that corresponds to a normalized |volume| of 1.5x.
291   DCHECK_LE(volume, 1.6);
292 #endif
293
294   // TODO(miu): Plumbing is needed to determine the actual capture timestamp
295   // of the audio, instead of just snapshotting TimeTicks::Now(), for proper
296   // audio/video sync.  http://crbug.com/335335
297   const base::TimeTicks reference_clock_snapshot = base::TimeTicks::Now();
298   TRACE_EVENT2("audio", "ProcessedLocalAudioSource::Capture", "now (ms)",
299                (reference_clock_snapshot - base::TimeTicks()).InMillisecondsF(),
300                "delay (ms)", audio_delay_milliseconds);
301
302   // Map internal volume range of [0.0, 1.0] into [0, 255] used by AGC.
303   // The volume can be higher than 255 on Linux, and it will be cropped to
304   // 255 since AGC does not allow values out of range.
305   int current_volume = static_cast<int>((volume * MaxVolume()) + 0.5);
306   // Note: Using NoBarrier_Store() because the timing of visibility of the
307   // updated volume information on other threads can be relaxed.
308   base::subtle::NoBarrier_Store(&volume_, current_volume);
309   current_volume = std::min(current_volume, MaxVolume());
310
311   // Sanity-check the input audio format in debug builds.  Then, notify the
312   // tracks if the format has changed.
313   //
314   // Locking is not needed here to read the audio input/output parameters
315   // because the audio processor format changes only occur while audio capture
316   // is stopped.
317   DCHECK(audio_processor_->InputFormat().IsValid());
318   DCHECK_EQ(audio_bus->channels(), audio_processor_->InputFormat().channels());
319   DCHECK_EQ(audio_bus->frames(),
320             audio_processor_->InputFormat().frames_per_buffer());
321
322   // Figure out if the pre-processed data has any energy or not. This
323   // information will be passed to the level calculator to force it to report
324   // energy in case the post-processed data is zeroed by the audio processing.
325   const bool force_report_nonzero_energy = !audio_bus->AreFramesZero();
326
327   // Push the data to the processor for processing.
328   audio_processor_->PushCaptureData(
329       *audio_bus,
330       base::TimeDelta::FromMilliseconds(audio_delay_milliseconds));
331
332   // Process and consume the data in the processor until there is not enough
333   // data in the processor.
334   media::AudioBus* processed_data = nullptr;
335   base::TimeDelta processed_data_audio_delay;
336   int new_volume = 0;
337   while (audio_processor_->ProcessAndConsumeData(
338              current_volume, key_pressed,
339              &processed_data, &processed_data_audio_delay, &new_volume)) {
340     DCHECK(processed_data);
341
342     level_calculator_.Calculate(*processed_data, force_report_nonzero_energy);
343
344     DeliverDataToTracks(*processed_data,
345                         reference_clock_snapshot - processed_data_audio_delay);
346
347     if (new_volume) {
348       SetVolume(new_volume);
349
350       // Update the |current_volume| to avoid passing the old volume to AGC.
351       current_volume = new_volume;
352     }
353   }
354 }
355
356 void ProcessedLocalAudioSource::OnCaptureError(const std::string& message) {
357   WebRtcLogMessage("ProcessedLocalAudioSource::OnCaptureError: " + message);
358   StopSourceOnError(message);
359 }
360
361 void ProcessedLocalAudioSource::OnCaptureMuted(bool is_muted) {
362   SetMutedState(is_muted);
363 }
364
365 media::AudioParameters ProcessedLocalAudioSource::GetInputFormat() const {
366   return audio_processor_ ? audio_processor_->InputFormat()
367                           : media::AudioParameters();
368 }
369
370 int ProcessedLocalAudioSource::GetBufferSize(int sample_rate) const {
371   DCHECK(thread_checker_.CalledOnValidThread());
372 #if defined(OS_ANDROID)
373   // TODO(henrika): Re-evaluate whether to use same logic as other platforms.
374   // http://crbug.com/638081
375   return (2 * sample_rate / 100);
376 #endif
377
378   // If audio processing is turned on, require 10ms buffers.
379   if (audio_processor_->has_audio_processing())
380     return (sample_rate / 100);
381
382   // If audio processing is off and the native hardware buffer size was
383   // provided, use it. It can be harmful, in terms of CPU/power consumption, to
384   // use smaller buffer sizes than the native size (http://crbug.com/362261).
385   if (int hardware_buffer_size = device().input.frames_per_buffer())
386     return hardware_buffer_size;
387
388   // If the buffer size is missing from the MediaStreamDevice, provide 10ms as a
389   // fall-back.
390   //
391   // TODO(miu): Identify where/why the buffer size might be missing, fix the
392   // code, and then require it here. http://crbug.com/638081
393   return (sample_rate / 100);
394 }
395
396 }  // namespace content