- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / media / webrtc_audio_capturer.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/webrtc_audio_capturer.h"
6
7 #include "base/bind.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"
16
17 namespace content {
18
19 namespace {
20
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};
32 #else
33 const int kValidInputRates[] = {44100};
34 #endif
35
36 }  // namespace
37
38 // Reference counted container of WebRtcLocalAudioTrack delegate.
39 class WebRtcAudioCapturer::TrackOwner
40     : public base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner> {
41  public:
42   explicit TrackOwner(WebRtcLocalAudioTrack* track)
43       : delegate_(track) {}
44
45   void Capture(media::AudioBus* audio_source,
46                int audio_delay_milliseconds,
47                double volume,
48                bool key_pressed) {
49     base::AutoLock lock(lock_);
50     if (delegate_) {
51       delegate_->Capture(audio_source,
52                          audio_delay_milliseconds,
53                          volume,
54                          key_pressed);
55     }
56   }
57
58   void SetCaptureFormat(const media::AudioParameters& params) {
59     base::AutoLock lock(lock_);
60     if (delegate_)
61       delegate_->SetCaptureFormat(params);
62   }
63
64   void Reset() {
65     base::AutoLock lock(lock_);
66     delegate_ = NULL;
67   }
68
69   // Wrapper which allows to use std::find_if() when adding and removing
70   // sinks to/from the list.
71   struct TrackWrapper {
72     TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {}
73     bool operator()(
74         const scoped_refptr<WebRtcAudioCapturer::TrackOwner>& owner) {
75       return owner->IsEqual(track_);
76     }
77     WebRtcLocalAudioTrack* track_;
78   };
79
80  protected:
81   virtual ~TrackOwner() {}
82
83  private:
84   friend class base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner>;
85
86   bool IsEqual(const WebRtcLocalAudioTrack* other) const {
87     base::AutoLock lock(lock_);
88     return (other == delegate_);
89   }
90
91   // Do NOT reference count the |delegate_| to avoid cyclic reference counting.
92   WebRtcLocalAudioTrack* delegate_;
93   mutable base::Lock lock_;
94
95   DISALLOW_COPY_AND_ASSIGN(TrackOwner);
96 };
97
98 // static
99 scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer() {
100   scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer();
101   return capturer;
102 }
103
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;
109
110   media::AudioParameters::Format format =
111       media::AudioParameters::AUDIO_PCM_LOW_LATENCY;
112
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);
117
118   TrackList tracks;
119   {
120     base::AutoLock auto_lock(lock_);
121     tracks = tracks_;
122     params_ = params;
123   }
124
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);
129 }
130
131 bool WebRtcAudioCapturer::Initialize(int render_view_id,
132                                      media::ChannelLayout channel_layout,
133                                      int sample_rate,
134                                      int buffer_size,
135                                      int session_id,
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()";
142
143   DVLOG(1) << "Audio input hardware channel layout: " << channel_layout;
144   UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout",
145                             channel_layout, media::CHANNEL_LAYOUT_MAX);
146
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;
153
154   if (render_view_id == -1) {
155     // Return true here to allow injecting a new source via SetCapturerSource()
156     // at a later state.
157     return true;
158   }
159
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.";
165     return false;
166   }
167
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);
173   } else {
174     UMA_HISTOGRAM_COUNTS("WebRTC.AudioInputSampleRateUnexpected", sample_rate);
175   }
176
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),
181                 sample_rate) ==
182           &kValidInputRates[arraysize(kValidInputRates)]) {
183     DLOG(ERROR) << sample_rate << " is not a supported input rate.";
184     return false;
185   }
186
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),
191                     channel_layout,
192                     static_cast<float>(sample_rate));
193
194   return true;
195 }
196
197 WebRtcAudioCapturer::WebRtcAudioCapturer()
198     : source_(NULL),
199       running_(false),
200       render_view_id_(-1),
201       hardware_buffer_size_(0),
202       session_id_(0),
203       volume_(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()";
210 }
211
212 WebRtcAudioCapturer::~WebRtcAudioCapturer() {
213   DCHECK(thread_checker_.CalledOnValidThread());
214   DCHECK(tracks_.empty());
215   DCHECK(!running_);
216   DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()";
217 }
218
219 void WebRtcAudioCapturer::AddTrack(WebRtcLocalAudioTrack* track) {
220   DCHECK(track);
221   DVLOG(1) << "WebRtcAudioCapturer::AddTrack()";
222
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.
225   Start();
226
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());
231
232   track->SetCaptureFormat(params_);
233   tracks_.push_back(new WebRtcAudioCapturer::TrackOwner(track));
234 }
235
236 void WebRtcAudioCapturer::RemoveTrack(WebRtcLocalAudioTrack* track) {
237   DCHECK(thread_checker_.CalledOnValidThread());
238
239   bool stop_source = false;
240   {
241     base::AutoLock auto_lock(lock_);
242     // Get iterator to the first element for which WrapsSink(track) returns
243     // true.
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.
250       (*it)->Reset();
251       tracks_.erase(it);
252     }
253
254     // Stop the source if the last audio track is going away.
255     stop_source = tracks_.empty();
256   }
257
258   if (stop_source)
259     Stop();
260 }
261
262 void WebRtcAudioCapturer::SetCapturerSource(
263     const scoped_refptr<media::AudioCapturerSource>& source,
264     media::ChannelLayout channel_layout,
265     float sample_rate) {
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;
271   {
272     base::AutoLock auto_lock(lock_);
273     if (source_.get() == source.get())
274       return;
275
276     source_.swap(old_source);
277     source_ = source;
278
279     // Reset the flag to allow starting the new source.
280     restart_source = running_;
281     running_ = false;
282   }
283
284   DVLOG(1) << "Switching to a new capture source.";
285   if (old_source.get())
286     old_source->Stop();
287
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);
292
293   // Make sure to grab the new parameters in case they were reconfigured.
294   media::AudioParameters params = audio_parameters();
295   source_provider_->Initialize(params);
296   if (source.get())
297     source->Initialize(params, this, session_id_);
298
299   if (restart_source)
300     Start();
301 }
302
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_)
308     return;
309
310   peer_connection_mode_ = true;
311   int render_view_id = -1;
312   {
313     base::AutoLock auto_lock(lock_);
314     // Simply return if there is no existing source or the |render_view_id_| is
315     // not valid.
316     if (!source_.get() || render_view_id_== -1)
317       return;
318
319     render_view_id = render_view_id_;
320   }
321
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())
325     return;
326
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()));
332 }
333
334 void WebRtcAudioCapturer::Start() {
335   DVLOG(1) << "WebRtcAudioCapturer::Start()";
336   base::AutoLock auto_lock(lock_);
337   if (running_)
338     return;
339
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.
342   if (source_.get()) {
343     // We need to set the AGC control before starting the stream.
344     source_->SetAutomaticGainControl(true);
345     source_->Start();
346   }
347
348   running_ = true;
349 }
350
351 void WebRtcAudioCapturer::Stop() {
352   DVLOG(1) << "WebRtcAudioCapturer::Stop()";
353   scoped_refptr<media::AudioCapturerSource> source;
354   {
355     base::AutoLock auto_lock(lock_);
356     if (!running_)
357       return;
358
359     source = source_;
360     running_ = false;
361   }
362
363   if (source.get())
364     source->Stop();
365 }
366
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_);
372   if (source_.get())
373     source_->SetVolume(normalized_volume);
374 }
375
376 int WebRtcAudioCapturer::Volume() const {
377   base::AutoLock auto_lock(lock_);
378   return volume_;
379 }
380
381 int WebRtcAudioCapturer::MaxVolume() const {
382   return WebRtcAudioDeviceImpl::kMaxVolumeLevel;
383 }
384
385 void WebRtcAudioCapturer::Capture(media::AudioBus* audio_source,
386                                   int audio_delay_milliseconds,
387                                   double volume,
388                                   bool key_pressed) {
389 // This callback is driven by AudioInputDevice::AudioThreadCallback if
390 // |source_| is AudioInputDevice, otherwise it is driven by client's
391 // CaptureCallback.
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);
401 #endif
402
403   TrackList tracks;
404   int current_volume = 0;
405   {
406     base::AutoLock auto_lock(lock_);
407     if (!running_)
408       return;
409
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_;
415     tracks = tracks_;
416   }
417
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);
422
423   // Feed the data to the tracks.
424   for (TrackList::const_iterator it = tracks.begin();
425        it != tracks.end();
426        ++it) {
427     (*it)->Capture(audio_source, audio_delay_milliseconds,
428                    current_volume, key_pressed);
429   }
430 }
431
432 void WebRtcAudioCapturer::OnCaptureError() {
433   NOTIMPLEMENTED();
434 }
435
436 media::AudioParameters WebRtcAudioCapturer::audio_parameters() const {
437   base::AutoLock auto_lock(lock_);
438   return params_;
439 }
440
441 bool WebRtcAudioCapturer::GetPairedOutputParameters(
442     int* session_id,
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;
450 }
451
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);
457 #endif
458
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_;
463 #endif
464
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);
468 }
469
470 }  // namespace content