Home | History | Annotate | Download | only in media
      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/audio_util.h"
     16 #include "media/audio/sample_rates.h"
     17 
     18 namespace content {
     19 
     20 namespace {
     21 
     22 // Supported hardware sample rates for input and output sides.
     23 #if defined(OS_WIN) || defined(OS_MACOSX)
     24 // media::GetAudioInputHardwareSampleRate() asks the audio layer
     25 // for its current sample rate (set by the user) on Windows and Mac OS X.
     26 // The listed rates below adds restrictions and WebRtcAudioDeviceImpl::Init()
     27 // will fail if the user selects any rate outside these ranges.
     28 const int kValidInputRates[] = {96000, 48000, 44100, 32000, 16000, 8000};
     29 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
     30 const int kValidInputRates[] = {48000, 44100};
     31 #elif defined(OS_ANDROID)
     32 const int kValidInputRates[] = {48000, 44100};
     33 #else
     34 const int kValidInputRates[] = {44100};
     35 #endif
     36 
     37 int GetBufferSizeForSampleRate(int sample_rate) {
     38   int buffer_size = 0;
     39 #if defined(OS_WIN) || defined(OS_MACOSX)
     40   // Use a buffer size of 10ms.
     41   buffer_size = (sample_rate / 100);
     42 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
     43   // Based on tests using the current ALSA implementation in Chrome, we have
     44   // found that the best combination is 20ms on the input side and 10ms on the
     45   // output side.
     46   buffer_size = 2 * sample_rate / 100;
     47 #elif defined(OS_ANDROID)
     48   // TODO(leozwang): Tune and adjust buffer size on Android.
     49     buffer_size = 2 * sample_rate / 100;
     50 #endif
     51   return buffer_size;
     52 }
     53 
     54 }  // namespace
     55 
     56 // This is a temporary audio buffer with parameters used to send data to
     57 // callbacks.
     58 class WebRtcAudioCapturer::ConfiguredBuffer :
     59     public base::RefCounted<WebRtcAudioCapturer::ConfiguredBuffer> {
     60  public:
     61   ConfiguredBuffer() {}
     62 
     63   bool Initialize(int sample_rate,
     64                   media::ChannelLayout channel_layout) {
     65     int buffer_size = GetBufferSizeForSampleRate(sample_rate);
     66     DVLOG(1) << "Using WebRTC input buffer size: " << buffer_size;
     67 
     68     media::AudioParameters::Format format =
     69         media::AudioParameters::AUDIO_PCM_LOW_LATENCY;
     70 
     71     // bits_per_sample is always 16 for now.
     72     int bits_per_sample = 16;
     73     int channels = ChannelLayoutToChannelCount(channel_layout);
     74     params_.Reset(format, channel_layout, channels, 0,
     75         sample_rate, bits_per_sample, buffer_size);
     76     buffer_.reset(new int16[params_.frames_per_buffer() * params_.channels()]);
     77 
     78     return true;
     79   }
     80 
     81   int16* buffer() const { return buffer_.get(); }
     82   const media::AudioParameters& params() const { return params_; }
     83 
     84  private:
     85   ~ConfiguredBuffer() {}
     86   friend class base::RefCounted<WebRtcAudioCapturer::ConfiguredBuffer>;
     87 
     88   scoped_ptr<int16[]> buffer_;
     89 
     90   // Cached values of utilized audio parameters.
     91   media::AudioParameters params_;
     92 };
     93 
     94 // Reference counted container of WebRtcLocalAudioTrack delegate.
     95 class WebRtcAudioCapturer::TrackOwner
     96     : public base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner> {
     97  public:
     98   explicit TrackOwner(WebRtcLocalAudioTrack* track)
     99       : delegate_(track) {}
    100 
    101   void CaptureData(const int16* audio_data,
    102                    int number_of_channels,
    103                    int number_of_frames,
    104                    int audio_delay_milliseconds,
    105                    int volume) {
    106     base::AutoLock lock(lock_);
    107     if (delegate_) {
    108       delegate_->CaptureData(audio_data,
    109                              number_of_channels,
    110                              number_of_frames,
    111                              audio_delay_milliseconds,
    112                              volume);
    113     }
    114   }
    115 
    116   void SetCaptureFormat(const media::AudioParameters& params) {
    117     base::AutoLock lock(lock_);
    118     if (delegate_)
    119       delegate_->SetCaptureFormat(params);
    120   }
    121 
    122   void Reset() {
    123     base::AutoLock lock(lock_);
    124     delegate_ = NULL;
    125   }
    126 
    127   // Wrapper which allows to use std::find_if() when adding and removing
    128   // sinks to/from the list.
    129   struct TrackWrapper {
    130     TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {}
    131     bool operator()(
    132         const scoped_refptr<WebRtcAudioCapturer::TrackOwner>& owner) {
    133       return owner->IsEqual(track_);
    134     }
    135     WebRtcLocalAudioTrack* track_;
    136   };
    137 
    138  protected:
    139   virtual ~TrackOwner() {}
    140 
    141  private:
    142   friend class base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner>;
    143 
    144   bool IsEqual(const WebRtcLocalAudioTrack* other) const {
    145     base::AutoLock lock(lock_);
    146     return (other == delegate_);
    147   }
    148 
    149   // Do NOT reference count the |delegate_| to avoid cyclic reference counting.
    150   WebRtcLocalAudioTrack* delegate_;
    151   mutable base::Lock lock_;
    152 
    153   DISALLOW_COPY_AND_ASSIGN(TrackOwner);
    154 };
    155 
    156 // static
    157 scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer() {
    158   scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer();
    159   return capturer;
    160 }
    161 
    162 bool WebRtcAudioCapturer::Reconfigure(int sample_rate,
    163                                       media::ChannelLayout channel_layout) {
    164   scoped_refptr<ConfiguredBuffer> new_buffer(new ConfiguredBuffer());
    165   if (!new_buffer->Initialize(sample_rate, channel_layout))
    166     return false;
    167 
    168   TrackList tracks;
    169   {
    170     base::AutoLock auto_lock(lock_);
    171 
    172     buffer_ = new_buffer;
    173     tracks = tracks_;
    174   }
    175 
    176   // Tell all audio_tracks which format we use.
    177   for (TrackList::const_iterator it = tracks.begin();
    178        it != tracks.end(); ++it)
    179     (*it)->SetCaptureFormat(new_buffer->params());
    180 
    181   return true;
    182 }
    183 
    184 bool WebRtcAudioCapturer::Initialize(int render_view_id,
    185                                      media::ChannelLayout channel_layout,
    186                                      int sample_rate,
    187                                      int session_id,
    188                                      const std::string& device_id) {
    189   DCHECK(thread_checker_.CalledOnValidThread());
    190   DVLOG(1) << "WebRtcAudioCapturer::Initialize()";
    191 
    192   DVLOG(1) << "Audio input hardware channel layout: " << channel_layout;
    193   UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout",
    194                             channel_layout, media::CHANNEL_LAYOUT_MAX);
    195 
    196   session_id_ = session_id;
    197   device_id_ = device_id;
    198   if (render_view_id == -1) {
    199     // This capturer is used by WebAudio, return true without creating a
    200     // default capturing source. WebAudio will inject its own source via
    201     // SetCapturerSource() at a later state.
    202     DCHECK(device_id.empty());
    203     return true;
    204   }
    205 
    206   // Verify that the reported input channel configuration is supported.
    207   if (channel_layout != media::CHANNEL_LAYOUT_MONO &&
    208       channel_layout != media::CHANNEL_LAYOUT_STEREO) {
    209     DLOG(ERROR) << channel_layout
    210                 << " is not a supported input channel configuration.";
    211     return false;
    212   }
    213 
    214   DVLOG(1) << "Audio input hardware sample rate: " << sample_rate;
    215   media::AudioSampleRate asr = media::AsAudioSampleRate(sample_rate);
    216   if (asr != media::kUnexpectedAudioSampleRate) {
    217     UMA_HISTOGRAM_ENUMERATION(
    218         "WebRTC.AudioInputSampleRate", asr, media::kUnexpectedAudioSampleRate);
    219   } else {
    220     UMA_HISTOGRAM_COUNTS("WebRTC.AudioInputSampleRateUnexpected", sample_rate);
    221   }
    222 
    223   // Verify that the reported input hardware sample rate is supported
    224   // on the current platform.
    225   if (std::find(&kValidInputRates[0],
    226                 &kValidInputRates[0] + arraysize(kValidInputRates),
    227                 sample_rate) ==
    228           &kValidInputRates[arraysize(kValidInputRates)]) {
    229     DLOG(ERROR) << sample_rate << " is not a supported input rate.";
    230     return false;
    231   }
    232 
    233   if (!Reconfigure(sample_rate, channel_layout))
    234     return false;
    235 
    236   // Create and configure the default audio capturing source. The |source_|
    237   // will be overwritten if an external client later calls SetCapturerSource()
    238   // providing an alternative media::AudioCapturerSource.
    239   SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id),
    240                     channel_layout,
    241                     static_cast<float>(sample_rate));
    242 
    243   return true;
    244 }
    245 
    246 WebRtcAudioCapturer::WebRtcAudioCapturer()
    247     : source_(NULL),
    248       running_(false),
    249       agc_is_enabled_(false),
    250       session_id_(0),
    251       volume_(0) {
    252   DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()";
    253 }
    254 
    255 WebRtcAudioCapturer::~WebRtcAudioCapturer() {
    256   DCHECK(thread_checker_.CalledOnValidThread());
    257   DCHECK(tracks_.empty());
    258   DCHECK(!running_);
    259   DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()";
    260 }
    261 
    262 void WebRtcAudioCapturer::AddTrack(WebRtcLocalAudioTrack* track) {
    263   DCHECK(track);
    264   DVLOG(1) << "WebRtcAudioCapturer::AddTrack()";
    265 
    266   // Start the source if the first audio track is connected to the capturer.
    267   // Start() will do nothing if the capturer has already been started.
    268   Start();
    269 
    270   base::AutoLock auto_lock(lock_);
    271   // Verify that |track| is not already added to the list.
    272   DCHECK(std::find_if(tracks_.begin(), tracks_.end(),
    273                       TrackOwner::TrackWrapper(track)) == tracks_.end());
    274 
    275   if (buffer_.get()) {
    276     track->SetCaptureFormat(buffer_->params());
    277   }
    278 
    279   tracks_.push_back(new WebRtcAudioCapturer::TrackOwner(track));
    280 }
    281 
    282 void WebRtcAudioCapturer::RemoveTrack(WebRtcLocalAudioTrack* track) {
    283   DCHECK(thread_checker_.CalledOnValidThread());
    284 
    285   bool stop_source = false;
    286   {
    287     base::AutoLock auto_lock(lock_);
    288     // Get iterator to the first element for which WrapsSink(track) returns
    289     // true.
    290     TrackList::iterator it = std::find_if(
    291         tracks_.begin(), tracks_.end(), TrackOwner::TrackWrapper(track));
    292     if (it != tracks_.end()) {
    293       // Clear the delegate to ensure that no more capture callbacks will
    294       // be sent to this sink. Also avoids a possible crash which can happen
    295       // if this method is called while capturing is active.
    296       (*it)->Reset();
    297       tracks_.erase(it);
    298     }
    299 
    300     // Stop the source if the last audio track is going away.
    301     stop_source = tracks_.empty();
    302   }
    303 
    304   if (stop_source)
    305     Stop();
    306 }
    307 
    308 void WebRtcAudioCapturer::SetCapturerSource(
    309     const scoped_refptr<media::AudioCapturerSource>& source,
    310     media::ChannelLayout channel_layout,
    311     float sample_rate) {
    312   DCHECK(thread_checker_.CalledOnValidThread());
    313   DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << ","
    314            << "sample_rate=" << sample_rate << ")";
    315   scoped_refptr<media::AudioCapturerSource> old_source;
    316   scoped_refptr<ConfiguredBuffer> current_buffer;
    317   bool restart_source = false;
    318   {
    319     base::AutoLock auto_lock(lock_);
    320     if (source_.get() == source.get())
    321       return;
    322 
    323     source_.swap(old_source);
    324     source_ = source;
    325     current_buffer = buffer_;
    326 
    327     // Reset the flag to allow starting the new source.
    328     restart_source = running_;
    329     running_ = false;
    330   }
    331 
    332   const bool no_default_audio_source_exists = !current_buffer.get();
    333 
    334   // Detach the old source from normal recording or perform first-time
    335   // initialization if Initialize() has never been called. For the second
    336   // case, the caller is not "taking over an ongoing session" but instead
    337   // "taking control over a new session".
    338   if (old_source.get() || no_default_audio_source_exists) {
    339     DVLOG(1) << "New capture source will now be utilized.";
    340     if (old_source.get())
    341       old_source->Stop();
    342 
    343     // Dispatch the new parameters both to the sink(s) and to the new source.
    344     // The idea is to get rid of any dependency of the microphone parameters
    345     // which would normally be used by default.
    346     if (!Reconfigure(sample_rate, channel_layout)) {
    347       return;
    348     } else {
    349       // The buffer has been reconfigured.  Update |current_buffer|.
    350       base::AutoLock auto_lock(lock_);
    351       current_buffer = buffer_;
    352     }
    353   }
    354 
    355   if (source.get()) {
    356     // Make sure to grab the new parameters in case they were reconfigured.
    357     source->Initialize(current_buffer->params(), this, session_id_);
    358   }
    359 
    360   if (restart_source)
    361     Start();
    362 }
    363 
    364 void WebRtcAudioCapturer::Start() {
    365   DVLOG(1) << "WebRtcAudioCapturer::Start()";
    366   base::AutoLock auto_lock(lock_);
    367   if (running_)
    368     return;
    369 
    370   // Start the data source, i.e., start capturing data from the current source.
    371   // Note that, the source does not have to be a microphone.
    372   if (source_.get()) {
    373     // We need to set the AGC control before starting the stream.
    374     source_->SetAutomaticGainControl(agc_is_enabled_);
    375     source_->Start();
    376   }
    377 
    378   running_ = true;
    379 }
    380 
    381 void WebRtcAudioCapturer::Stop() {
    382   DVLOG(1) << "WebRtcAudioCapturer::Stop()";
    383   scoped_refptr<media::AudioCapturerSource> source;
    384   {
    385     base::AutoLock auto_lock(lock_);
    386     if (!running_)
    387       return;
    388 
    389     source = source_;
    390     running_ = false;
    391   }
    392 
    393   if (source.get())
    394     source->Stop();
    395 }
    396 
    397 void WebRtcAudioCapturer::SetVolume(int volume) {
    398   DVLOG(1) << "WebRtcAudioCapturer::SetVolume()";
    399   DCHECK_LE(volume, MaxVolume());
    400   double normalized_volume = static_cast<double>(volume) / MaxVolume();
    401   base::AutoLock auto_lock(lock_);
    402   if (source_.get())
    403     source_->SetVolume(normalized_volume);
    404 }
    405 
    406 int WebRtcAudioCapturer::Volume() const {
    407   base::AutoLock auto_lock(lock_);
    408   return volume_;
    409 }
    410 
    411 int WebRtcAudioCapturer::MaxVolume() const {
    412   return WebRtcAudioDeviceImpl::kMaxVolumeLevel;
    413 }
    414 
    415 void WebRtcAudioCapturer::SetAutomaticGainControl(bool enable) {
    416   base::AutoLock auto_lock(lock_);
    417   // Store the setting since SetAutomaticGainControl() can be called before
    418   // Initialize(), in this case stored setting will be applied in Start().
    419   agc_is_enabled_ = enable;
    420 
    421   if (source_.get())
    422     source_->SetAutomaticGainControl(enable);
    423 }
    424 
    425 void WebRtcAudioCapturer::Capture(media::AudioBus* audio_source,
    426                                   int audio_delay_milliseconds,
    427                                   double volume) {
    428   // This callback is driven by AudioInputDevice::AudioThreadCallback if
    429   // |source_| is AudioInputDevice, otherwise it is driven by client's
    430   // CaptureCallback.
    431 #if defined(OS_WIN) || defined(OS_MACOSX)
    432   DCHECK_LE(volume, 1.0);
    433 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
    434   // We have a special situation on Linux where the microphone volume can be
    435   // "higher than maximum". The input volume slider in the sound preference
    436   // allows the user to set a scaling that is higher than 100%. It means that
    437   // even if the reported maximum levels is N, the actual microphone level can
    438   // go up to 1.5x*N and that corresponds to a normalized |volume| of 1.5x.
    439   DCHECK_LE(volume, 1.6);
    440 #endif
    441 
    442   TrackList tracks;
    443   scoped_refptr<ConfiguredBuffer> buffer_ref_while_calling;
    444   {
    445     base::AutoLock auto_lock(lock_);
    446     if (!running_)
    447       return;
    448 
    449     // Map internal volume range of [0.0, 1.0] into [0, 255] used by the
    450     // webrtc::VoiceEngine. webrtc::VoiceEngine will handle the case when the
    451     // volume is higher than 255.
    452     volume_ = static_cast<int>((volume * MaxVolume()) + 0.5);
    453 
    454     // Copy the stuff we will need to local variables. In particular, we grab
    455     // a reference to the buffer so we can ensure it stays alive even if the
    456     // buffer is reconfigured while we are calling back.
    457     buffer_ref_while_calling = buffer_;
    458     tracks = tracks_;
    459   }
    460 
    461   int bytes_per_sample =
    462       buffer_ref_while_calling->params().bits_per_sample() / 8;
    463 
    464   // Interleave, scale, and clip input to int and store result in
    465   // a local byte buffer.
    466   audio_source->ToInterleaved(audio_source->frames(), bytes_per_sample,
    467                               buffer_ref_while_calling->buffer());
    468 
    469   // Feed the data to the tracks.
    470   for (TrackList::const_iterator it = tracks.begin();
    471        it != tracks.end();
    472        ++it) {
    473     (*it)->CaptureData(buffer_ref_while_calling->buffer(),
    474                        audio_source->channels(), audio_source->frames(),
    475                        audio_delay_milliseconds, volume_);
    476   }
    477 }
    478 
    479 void WebRtcAudioCapturer::OnCaptureError() {
    480   NOTIMPLEMENTED();
    481 }
    482 
    483 media::AudioParameters WebRtcAudioCapturer::audio_parameters() const {
    484   base::AutoLock auto_lock(lock_);
    485   // |buffer_| can be NULL when SetCapturerSource() or Initialize() has not
    486   // been called.
    487   return buffer_.get() ? buffer_->params() : media::AudioParameters();
    488 }
    489 
    490 }  // namespace content
    491