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.
5 #include "content/renderer/media/webrtc_audio_capturer.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_util.h"
11 #include "content/child/child_process.h"
12 #include "content/renderer/media/audio_device_factory.h"
13 #include "content/renderer/media/webrtc_audio_device_impl.h"
14 #include "content/renderer/media/webrtc_local_audio_track.h"
15 #include "media/audio/sample_rates.h"
21 // Supported hardware sample rates for input and output sides.
22 #if defined(OS_WIN) || defined(OS_MACOSX)
23 // media::GetAudioInputHardwareSampleRate() asks the audio layer
24 // for its current sample rate (set by the user) on Windows and Mac OS X.
25 // The listed rates below adds restrictions and WebRtcAudioDeviceImpl::Init()
26 // will fail if the user selects any rate outside these ranges.
27 const int kValidInputRates[] = {96000, 48000, 44100, 32000, 16000, 8000};
28 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
29 const int kValidInputRates[] = {48000, 44100};
30 #elif defined(OS_ANDROID)
31 const int kValidInputRates[] = {48000, 44100};
33 const int kValidInputRates[] = {44100};
38 // Reference counted container of WebRtcLocalAudioTrack delegate.
39 class WebRtcAudioCapturer::TrackOwner
40 : public base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner> {
42 explicit TrackOwner(WebRtcLocalAudioTrack* track)
45 void Capture(media::AudioBus* audio_source,
46 int audio_delay_milliseconds,
49 base::AutoLock lock(lock_);
51 delegate_->Capture(audio_source,
52 audio_delay_milliseconds,
58 void SetCaptureFormat(const media::AudioParameters& params) {
59 base::AutoLock lock(lock_);
61 delegate_->SetCaptureFormat(params);
65 base::AutoLock lock(lock_);
69 // Wrapper which allows to use std::find_if() when adding and removing
70 // sinks to/from the list.
72 TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {}
74 const scoped_refptr<WebRtcAudioCapturer::TrackOwner>& owner) {
75 return owner->IsEqual(track_);
77 WebRtcLocalAudioTrack* track_;
81 virtual ~TrackOwner() {}
84 friend class base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner>;
86 bool IsEqual(const WebRtcLocalAudioTrack* other) const {
87 base::AutoLock lock(lock_);
88 return (other == delegate_);
91 // Do NOT reference count the |delegate_| to avoid cyclic reference counting.
92 WebRtcLocalAudioTrack* delegate_;
93 mutable base::Lock lock_;
95 DISALLOW_COPY_AND_ASSIGN(TrackOwner);
99 scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer() {
100 scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer();
104 void WebRtcAudioCapturer::Reconfigure(int sample_rate,
105 media::ChannelLayout channel_layout) {
106 DCHECK(thread_checker_.CalledOnValidThread());
107 int buffer_size = GetBufferSize(sample_rate);
108 DVLOG(1) << "Using WebRTC input buffer size: " << buffer_size;
110 media::AudioParameters::Format format =
111 media::AudioParameters::AUDIO_PCM_LOW_LATENCY;
113 // bits_per_sample is always 16 for now.
114 int bits_per_sample = 16;
115 media::AudioParameters params(format, channel_layout, sample_rate,
116 bits_per_sample, buffer_size);
120 base::AutoLock auto_lock(lock_);
125 // Tell all audio_tracks which format we use.
126 for (TrackList::const_iterator it = tracks.begin();
127 it != tracks.end(); ++it)
128 (*it)->SetCaptureFormat(params);
131 bool WebRtcAudioCapturer::Initialize(int render_view_id,
132 media::ChannelLayout channel_layout,
136 const std::string& device_id,
137 int paired_output_sample_rate,
138 int paired_output_frames_per_buffer) {
139 DCHECK(thread_checker_.CalledOnValidThread());
140 DCHECK_GE(render_view_id, 0);
141 DVLOG(1) << "WebRtcAudioCapturer::Initialize()";
143 DVLOG(1) << "Audio input hardware channel layout: " << channel_layout;
144 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout",
145 channel_layout, media::CHANNEL_LAYOUT_MAX);
147 render_view_id_ = render_view_id;
148 session_id_ = session_id;
149 device_id_ = device_id;
150 hardware_buffer_size_ = buffer_size;
151 output_sample_rate_ = paired_output_sample_rate;
152 output_frames_per_buffer_= paired_output_frames_per_buffer;
154 if (render_view_id == -1) {
155 // Return true here to allow injecting a new source via SetCapturerSource()
160 // Verify that the reported input channel configuration is supported.
161 if (channel_layout != media::CHANNEL_LAYOUT_MONO &&
162 channel_layout != media::CHANNEL_LAYOUT_STEREO) {
163 DLOG(ERROR) << channel_layout
164 << " is not a supported input channel configuration.";
168 DVLOG(1) << "Audio input hardware sample rate: " << sample_rate;
169 media::AudioSampleRate asr = media::AsAudioSampleRate(sample_rate);
170 if (asr != media::kUnexpectedAudioSampleRate) {
171 UMA_HISTOGRAM_ENUMERATION(
172 "WebRTC.AudioInputSampleRate", asr, media::kUnexpectedAudioSampleRate);
174 UMA_HISTOGRAM_COUNTS("WebRTC.AudioInputSampleRateUnexpected", sample_rate);
177 // Verify that the reported input hardware sample rate is supported
178 // on the current platform.
179 if (std::find(&kValidInputRates[0],
180 &kValidInputRates[0] + arraysize(kValidInputRates),
182 &kValidInputRates[arraysize(kValidInputRates)]) {
183 DLOG(ERROR) << sample_rate << " is not a supported input rate.";
187 // Create and configure the default audio capturing source. The |source_|
188 // will be overwritten if an external client later calls SetCapturerSource()
189 // providing an alternative media::AudioCapturerSource.
190 SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id),
192 static_cast<float>(sample_rate));
197 WebRtcAudioCapturer::WebRtcAudioCapturer()
201 hardware_buffer_size_(0),
204 source_provider_(new WebRtcLocalAudioSourceProvider()),
205 peer_connection_mode_(false),
206 output_sample_rate_(0),
207 output_frames_per_buffer_(0) {
208 DCHECK(source_provider_.get());
209 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()";
212 WebRtcAudioCapturer::~WebRtcAudioCapturer() {
213 DCHECK(thread_checker_.CalledOnValidThread());
214 DCHECK(tracks_.empty());
216 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()";
219 void WebRtcAudioCapturer::AddTrack(WebRtcLocalAudioTrack* track) {
221 DVLOG(1) << "WebRtcAudioCapturer::AddTrack()";
223 // Start the source if the first audio track is connected to the capturer.
224 // Start() will do nothing if the capturer has already been started.
227 base::AutoLock auto_lock(lock_);
228 // Verify that |track| is not already added to the list.
229 DCHECK(std::find_if(tracks_.begin(), tracks_.end(),
230 TrackOwner::TrackWrapper(track)) == tracks_.end());
232 track->SetCaptureFormat(params_);
233 tracks_.push_back(new WebRtcAudioCapturer::TrackOwner(track));
236 void WebRtcAudioCapturer::RemoveTrack(WebRtcLocalAudioTrack* track) {
237 DCHECK(thread_checker_.CalledOnValidThread());
239 bool stop_source = false;
241 base::AutoLock auto_lock(lock_);
242 // Get iterator to the first element for which WrapsSink(track) returns
244 TrackList::iterator it = std::find_if(
245 tracks_.begin(), tracks_.end(), TrackOwner::TrackWrapper(track));
246 if (it != tracks_.end()) {
247 // Clear the delegate to ensure that no more capture callbacks will
248 // be sent to this sink. Also avoids a possible crash which can happen
249 // if this method is called while capturing is active.
254 // Stop the source if the last audio track is going away.
255 stop_source = tracks_.empty();
262 void WebRtcAudioCapturer::SetCapturerSource(
263 const scoped_refptr<media::AudioCapturerSource>& source,
264 media::ChannelLayout channel_layout,
266 DCHECK(thread_checker_.CalledOnValidThread());
267 DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << ","
268 << "sample_rate=" << sample_rate << ")";
269 scoped_refptr<media::AudioCapturerSource> old_source;
270 bool restart_source = false;
272 base::AutoLock auto_lock(lock_);
273 if (source_.get() == source.get())
276 source_.swap(old_source);
279 // Reset the flag to allow starting the new source.
280 restart_source = running_;
284 DVLOG(1) << "Switching to a new capture source.";
285 if (old_source.get())
288 // Dispatch the new parameters both to the sink(s) and to the new source.
289 // The idea is to get rid of any dependency of the microphone parameters
290 // which would normally be used by default.
291 Reconfigure(sample_rate, channel_layout);
293 // Make sure to grab the new parameters in case they were reconfigured.
294 media::AudioParameters params = audio_parameters();
295 source_provider_->Initialize(params);
297 source->Initialize(params, this, session_id_);
303 void WebRtcAudioCapturer::EnablePeerConnectionMode() {
304 DCHECK(thread_checker_.CalledOnValidThread());
305 DVLOG(1) << "EnablePeerConnectionMode";
306 // Do nothing if the peer connection mode has been enabled.
307 if (peer_connection_mode_)
310 peer_connection_mode_ = true;
311 int render_view_id = -1;
313 base::AutoLock auto_lock(lock_);
314 // Simply return if there is no existing source or the |render_view_id_| is
316 if (!source_.get() || render_view_id_== -1)
319 render_view_id = render_view_id_;
322 // Do nothing if the current buffer size is the WebRtc native buffer size.
323 media::AudioParameters params = audio_parameters();
324 if (GetBufferSize(params.sample_rate()) == params.frames_per_buffer())
327 // Create a new audio stream as source which will open the hardware using
328 // WebRtc native buffer size.
329 SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id),
330 params.channel_layout(),
331 static_cast<float>(params.sample_rate()));
334 void WebRtcAudioCapturer::Start() {
335 DVLOG(1) << "WebRtcAudioCapturer::Start()";
336 base::AutoLock auto_lock(lock_);
340 // Start the data source, i.e., start capturing data from the current source.
341 // Note that, the source does not have to be a microphone.
343 // We need to set the AGC control before starting the stream.
344 source_->SetAutomaticGainControl(true);
351 void WebRtcAudioCapturer::Stop() {
352 DVLOG(1) << "WebRtcAudioCapturer::Stop()";
353 scoped_refptr<media::AudioCapturerSource> source;
355 base::AutoLock auto_lock(lock_);
367 void WebRtcAudioCapturer::SetVolume(int volume) {
368 DVLOG(1) << "WebRtcAudioCapturer::SetVolume()";
369 DCHECK_LE(volume, MaxVolume());
370 double normalized_volume = static_cast<double>(volume) / MaxVolume();
371 base::AutoLock auto_lock(lock_);
373 source_->SetVolume(normalized_volume);
376 int WebRtcAudioCapturer::Volume() const {
377 base::AutoLock auto_lock(lock_);
381 int WebRtcAudioCapturer::MaxVolume() const {
382 return WebRtcAudioDeviceImpl::kMaxVolumeLevel;
385 void WebRtcAudioCapturer::Capture(media::AudioBus* audio_source,
386 int audio_delay_milliseconds,
389 // This callback is driven by AudioInputDevice::AudioThreadCallback if
390 // |source_| is AudioInputDevice, otherwise it is driven by client's
392 #if defined(OS_WIN) || defined(OS_MACOSX)
393 DCHECK_LE(volume, 1.0);
394 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
395 // We have a special situation on Linux where the microphone volume can be
396 // "higher than maximum". The input volume slider in the sound preference
397 // allows the user to set a scaling that is higher than 100%. It means that
398 // even if the reported maximum levels is N, the actual microphone level can
399 // go up to 1.5x*N and that corresponds to a normalized |volume| of 1.5x.
400 DCHECK_LE(volume, 1.6);
404 int current_volume = 0;
406 base::AutoLock auto_lock(lock_);
410 // Map internal volume range of [0.0, 1.0] into [0, 255] used by the
411 // webrtc::VoiceEngine. webrtc::VoiceEngine will handle the case when the
412 // volume is higher than 255.
413 volume_ = static_cast<int>((volume * MaxVolume()) + 0.5);
414 current_volume = volume_;
418 // Deliver captured data to source provider, which stores the data into FIFO
419 // for WebAudio to fetch.
420 source_provider_->DeliverData(audio_source, audio_delay_milliseconds,
421 current_volume, key_pressed);
423 // Feed the data to the tracks.
424 for (TrackList::const_iterator it = tracks.begin();
427 (*it)->Capture(audio_source, audio_delay_milliseconds,
428 current_volume, key_pressed);
432 void WebRtcAudioCapturer::OnCaptureError() {
436 media::AudioParameters WebRtcAudioCapturer::audio_parameters() const {
437 base::AutoLock auto_lock(lock_);
441 bool WebRtcAudioCapturer::GetPairedOutputParameters(
443 int* output_sample_rate,
444 int* output_frames_per_buffer) const {
445 *session_id = session_id_;
446 *output_sample_rate = output_sample_rate_;
447 *output_frames_per_buffer = output_frames_per_buffer_;
448 return session_id_ > 0 && output_sample_rate_ > 0 &&
449 output_frames_per_buffer_> 0;
452 int WebRtcAudioCapturer::GetBufferSize(int sample_rate) const {
453 DCHECK(thread_checker_.CalledOnValidThread());
454 #if defined(OS_ANDROID)
455 // TODO(henrika): Tune and adjust buffer size on Android.
456 return (2 * sample_rate / 100);
459 #if defined(OS_MACOSX)
460 // Use the native hardware buffer size in non peer connection mode on Mac.
461 if (!peer_connection_mode_ && hardware_buffer_size_)
462 return hardware_buffer_size_;
465 // WebRtc is running at a buffer size of 10ms data. Use a multiple of 10ms
466 // as the buffer size to achieve the best performance for WebRtc.
467 return (sample_rate / 100);
470 } // namespace content