Home | History | Annotate | Download | only in media
      1 // Copyright 2013 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_device_impl.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/metrics/histogram.h"
      9 #include "base/strings/string_util.h"
     10 #include "base/win/windows_version.h"
     11 #include "content/renderer/media/webrtc_audio_capturer.h"
     12 #include "content/renderer/media/webrtc_audio_renderer.h"
     13 #include "content/renderer/render_thread_impl.h"
     14 #include "media/audio/audio_parameters.h"
     15 #include "media/audio/sample_rates.h"
     16 
     17 using media::AudioParameters;
     18 using media::ChannelLayout;
     19 
     20 namespace content {
     21 
     22 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()
     23     : ref_count_(0),
     24       audio_transport_callback_(NULL),
     25       input_delay_ms_(0),
     26       output_delay_ms_(0),
     27       initialized_(false),
     28       playing_(false),
     29       recording_(false),
     30       microphone_volume_(0) {
     31   DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()";
     32 }
     33 
     34 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() {
     35   DVLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()";
     36   DCHECK(thread_checker_.CalledOnValidThread());
     37   Terminate();
     38 }
     39 
     40 int32_t WebRtcAudioDeviceImpl::AddRef() {
     41   DCHECK(thread_checker_.CalledOnValidThread());
     42   return base::subtle::Barrier_AtomicIncrement(&ref_count_, 1);
     43 }
     44 
     45 int32_t WebRtcAudioDeviceImpl::Release() {
     46   DCHECK(thread_checker_.CalledOnValidThread());
     47   int ret = base::subtle::Barrier_AtomicIncrement(&ref_count_, -1);
     48   if (ret == 0) {
     49     delete this;
     50   }
     51   return ret;
     52 }
     53 int WebRtcAudioDeviceImpl::OnData(const int16* audio_data,
     54                                   int sample_rate,
     55                                   int number_of_channels,
     56                                   int number_of_frames,
     57                                   const std::vector<int>& channels,
     58                                   int audio_delay_milliseconds,
     59                                   int current_volume,
     60                                   bool need_audio_processing,
     61                                   bool key_pressed) {
     62   int total_delay_ms = 0;
     63   {
     64     base::AutoLock auto_lock(lock_);
     65     // Return immediately when not recording or |channels| is empty.
     66     // See crbug.com/274017: renderer crash dereferencing invalid channels[0].
     67     if (!recording_ || channels.empty())
     68       return 0;
     69 
     70     // Store the reported audio delay locally.
     71     input_delay_ms_ = audio_delay_milliseconds;
     72     total_delay_ms = input_delay_ms_ + output_delay_ms_;
     73     DVLOG(2) << "total delay: " << input_delay_ms_ + output_delay_ms_;
     74   }
     75 
     76   // Write audio samples in blocks of 10 milliseconds to the registered
     77   // webrtc::AudioTransport sink. Keep writing until our internal byte
     78   // buffer is empty.
     79   const int16* audio_buffer = audio_data;
     80   const int samples_per_10_msec = (sample_rate / 100);
     81   CHECK_EQ(number_of_frames % samples_per_10_msec, 0);
     82   int accumulated_audio_samples = 0;
     83   uint32_t new_volume = 0;
     84   while (accumulated_audio_samples < number_of_frames) {
     85     // Deliver 10ms of recorded 16-bit linear PCM audio.
     86     int new_mic_level = audio_transport_callback_->OnDataAvailable(
     87         &channels[0],
     88         channels.size(),
     89         audio_buffer,
     90         sample_rate,
     91         number_of_channels,
     92         samples_per_10_msec,
     93         total_delay_ms,
     94         current_volume,
     95         key_pressed,
     96         need_audio_processing);
     97 
     98     accumulated_audio_samples += samples_per_10_msec;
     99     audio_buffer += samples_per_10_msec * number_of_channels;
    100 
    101     // The latest non-zero new microphone level will be returned.
    102     if (new_mic_level)
    103       new_volume = new_mic_level;
    104   }
    105 
    106   return new_volume;
    107 }
    108 
    109 void WebRtcAudioDeviceImpl::OnSetFormat(
    110     const media::AudioParameters& params) {
    111   DVLOG(1) << "WebRtcAudioDeviceImpl::OnSetFormat()";
    112 }
    113 
    114 void WebRtcAudioDeviceImpl::RenderData(uint8* audio_data,
    115                                        int number_of_channels,
    116                                        int number_of_frames,
    117                                        int audio_delay_milliseconds) {
    118   DCHECK_LE(number_of_frames, output_buffer_size());
    119   {
    120     base::AutoLock auto_lock(lock_);
    121     DCHECK(audio_transport_callback_);
    122     // Store the reported audio delay locally.
    123     output_delay_ms_ = audio_delay_milliseconds;
    124   }
    125 
    126   const int channels = number_of_channels;
    127   DCHECK_LE(channels, output_channels());
    128 
    129   int samples_per_sec = output_sample_rate();
    130   int samples_per_10_msec = (samples_per_sec / 100);
    131   int bytes_per_sample = output_audio_parameters_.bits_per_sample() / 8;
    132   const int bytes_per_10_msec =
    133       channels * samples_per_10_msec * bytes_per_sample;
    134 
    135   uint32_t num_audio_samples = 0;
    136   int accumulated_audio_samples = 0;
    137 
    138   // Get audio samples in blocks of 10 milliseconds from the registered
    139   // webrtc::AudioTransport source. Keep reading until our internal buffer
    140   // is full.
    141   while (accumulated_audio_samples < number_of_frames) {
    142     // Get 10ms and append output to temporary byte buffer.
    143     audio_transport_callback_->NeedMorePlayData(samples_per_10_msec,
    144                                                 bytes_per_sample,
    145                                                 channels,
    146                                                 samples_per_sec,
    147                                                 audio_data,
    148                                                 num_audio_samples);
    149     accumulated_audio_samples += num_audio_samples;
    150     audio_data += bytes_per_10_msec;
    151   }
    152 }
    153 
    154 void WebRtcAudioDeviceImpl::SetRenderFormat(const AudioParameters& params) {
    155   DCHECK(thread_checker_.CalledOnValidThread());
    156   output_audio_parameters_ = params;
    157 }
    158 
    159 void WebRtcAudioDeviceImpl::RemoveAudioRenderer(WebRtcAudioRenderer* renderer) {
    160   DCHECK(thread_checker_.CalledOnValidThread());
    161   DCHECK_EQ(renderer, renderer_);
    162   base::AutoLock auto_lock(lock_);
    163   renderer_ = NULL;
    164   playing_ = false;
    165 }
    166 
    167 int32_t WebRtcAudioDeviceImpl::RegisterAudioCallback(
    168     webrtc::AudioTransport* audio_callback) {
    169   DVLOG(1) << "WebRtcAudioDeviceImpl::RegisterAudioCallback()";
    170   DCHECK(thread_checker_.CalledOnValidThread());
    171   DCHECK_EQ(audio_transport_callback_ == NULL, audio_callback != NULL);
    172   audio_transport_callback_ = audio_callback;
    173   return 0;
    174 }
    175 
    176 int32_t WebRtcAudioDeviceImpl::Init() {
    177   DVLOG(1) << "WebRtcAudioDeviceImpl::Init()";
    178   DCHECK(thread_checker_.CalledOnValidThread());
    179 
    180   // We need to return a success to continue the initialization of WebRtc VoE
    181   // because failure on the capturer_ initialization should not prevent WebRTC
    182   // from working. See issue http://crbug.com/144421 for details.
    183   initialized_ = true;
    184 
    185   return 0;
    186 }
    187 
    188 int32_t WebRtcAudioDeviceImpl::Terminate() {
    189   DVLOG(1) << "WebRtcAudioDeviceImpl::Terminate()";
    190   DCHECK(thread_checker_.CalledOnValidThread());
    191 
    192   // Calling Terminate() multiple times in a row is OK.
    193   if (!initialized_)
    194     return 0;
    195 
    196   StopRecording();
    197   StopPlayout();
    198 
    199   DCHECK(!renderer_.get() || !renderer_->IsStarted())
    200       << "The shared audio renderer shouldn't be running";
    201 
    202   capturers_.clear();
    203 
    204   initialized_ = false;
    205   return 0;
    206 }
    207 
    208 bool WebRtcAudioDeviceImpl::Initialized() const {
    209   return initialized_;
    210 }
    211 
    212 int32_t WebRtcAudioDeviceImpl::PlayoutIsAvailable(bool* available) {
    213   *available = initialized_;
    214   return 0;
    215 }
    216 
    217 bool WebRtcAudioDeviceImpl::PlayoutIsInitialized() const {
    218   return initialized_;
    219 }
    220 
    221 int32_t WebRtcAudioDeviceImpl::RecordingIsAvailable(bool* available) {
    222   *available = (!capturers_.empty());
    223   return 0;
    224 }
    225 
    226 bool WebRtcAudioDeviceImpl::RecordingIsInitialized() const {
    227   DVLOG(1) << "WebRtcAudioDeviceImpl::RecordingIsInitialized()";
    228   DCHECK(thread_checker_.CalledOnValidThread());
    229   return (!capturers_.empty());
    230 }
    231 
    232 int32_t WebRtcAudioDeviceImpl::StartPlayout() {
    233   DVLOG(1) << "WebRtcAudioDeviceImpl::StartPlayout()";
    234   LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing";
    235   {
    236     base::AutoLock auto_lock(lock_);
    237     if (!audio_transport_callback_)
    238       return 0;
    239   }
    240 
    241   if (playing_) {
    242     // webrtc::VoiceEngine assumes that it is OK to call Start() twice and
    243     // that the call is ignored the second time.
    244     return 0;
    245   }
    246 
    247   playing_ = true;
    248   start_render_time_ = base::Time::Now();
    249   return 0;
    250 }
    251 
    252 int32_t WebRtcAudioDeviceImpl::StopPlayout() {
    253   DVLOG(1) << "WebRtcAudioDeviceImpl::StopPlayout()";
    254   if (!playing_) {
    255     // webrtc::VoiceEngine assumes that it is OK to call Stop() just in case.
    256     return 0;
    257   }
    258 
    259   // Add histogram data to be uploaded as part of an UMA logging event.
    260   // This histogram keeps track of total playout times.
    261   if (!start_render_time_.is_null()) {
    262     base::TimeDelta render_time = base::Time::Now() - start_render_time_;
    263     UMA_HISTOGRAM_LONG_TIMES("WebRTC.AudioRenderTime", render_time);
    264   }
    265 
    266   playing_ = false;
    267   return 0;
    268 }
    269 
    270 bool WebRtcAudioDeviceImpl::Playing() const {
    271   return playing_;
    272 }
    273 
    274 int32_t WebRtcAudioDeviceImpl::StartRecording() {
    275   DVLOG(1) << "WebRtcAudioDeviceImpl::StartRecording()";
    276   DCHECK(initialized_);
    277   LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing";
    278   if (!audio_transport_callback_) {
    279     return -1;
    280   }
    281 
    282   {
    283     base::AutoLock auto_lock(lock_);
    284     if (recording_)
    285       return 0;
    286 
    287     recording_ = true;
    288   }
    289 
    290   start_capture_time_ = base::Time::Now();
    291 
    292   return 0;
    293 }
    294 
    295 int32_t WebRtcAudioDeviceImpl::StopRecording() {
    296   DVLOG(1) << "WebRtcAudioDeviceImpl::StopRecording()";
    297   {
    298     base::AutoLock auto_lock(lock_);
    299     if (!recording_)
    300       return 0;
    301 
    302     recording_ = false;
    303   }
    304 
    305   // Add histogram data to be uploaded as part of an UMA logging event.
    306   // This histogram keeps track of total recording times.
    307   if (!start_capture_time_.is_null()) {
    308     base::TimeDelta capture_time = base::Time::Now() - start_capture_time_;
    309     UMA_HISTOGRAM_LONG_TIMES("WebRTC.AudioCaptureTime", capture_time);
    310   }
    311 
    312   return 0;
    313 }
    314 
    315 bool WebRtcAudioDeviceImpl::Recording() const {
    316   base::AutoLock auto_lock(lock_);
    317   return recording_;
    318 }
    319 
    320 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) {
    321   DVLOG(1) << "WebRtcAudioDeviceImpl::SetMicrophoneVolume(" << volume << ")";
    322   DCHECK(initialized_);
    323 
    324   // Only one microphone is supported at the moment, which is represented by
    325   // the default capturer.
    326   scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
    327   if (!capturer.get())
    328     return -1;
    329 
    330   capturer->SetVolume(volume);
    331   return 0;
    332 }
    333 
    334 // TODO(henrika): sort out calling thread once we start using this API.
    335 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const {
    336   DVLOG(1) << "WebRtcAudioDeviceImpl::MicrophoneVolume()";
    337   // We only support one microphone now, which is accessed via the default
    338   // capturer.
    339   DCHECK(initialized_);
    340   scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
    341   if (!capturer.get())
    342     return -1;
    343 
    344   *volume = static_cast<uint32_t>(capturer->Volume());
    345 
    346   return 0;
    347 }
    348 
    349 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const {
    350   DCHECK(initialized_);
    351   *max_volume = kMaxVolumeLevel;
    352   return 0;
    353 }
    354 
    355 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const {
    356   *min_volume = 0;
    357   return 0;
    358 }
    359 
    360 int32_t WebRtcAudioDeviceImpl::StereoPlayoutIsAvailable(bool* available) const {
    361   DCHECK(initialized_);
    362   *available = (output_channels() == 2);
    363   return 0;
    364 }
    365 
    366 int32_t WebRtcAudioDeviceImpl::StereoRecordingIsAvailable(
    367     bool* available) const {
    368   DCHECK(initialized_);
    369   // TODO(xians): These kind of hardware methods do not make much sense since we
    370   // support multiple sources. Remove or figure out new APIs for such methods.
    371   scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
    372   if (!capturer.get())
    373     return -1;
    374 
    375   *available = (capturer->audio_parameters().channels() == 2);
    376   return 0;
    377 }
    378 
    379 int32_t WebRtcAudioDeviceImpl::PlayoutDelay(uint16_t* delay_ms) const {
    380   base::AutoLock auto_lock(lock_);
    381   *delay_ms = static_cast<uint16_t>(output_delay_ms_);
    382   return 0;
    383 }
    384 
    385 int32_t WebRtcAudioDeviceImpl::RecordingDelay(uint16_t* delay_ms) const {
    386   base::AutoLock auto_lock(lock_);
    387   *delay_ms = static_cast<uint16_t>(input_delay_ms_);
    388   return 0;
    389 }
    390 
    391 int32_t WebRtcAudioDeviceImpl::RecordingSampleRate(
    392     uint32_t* samples_per_sec) const {
    393   // We use the default capturer as the recording sample rate.
    394   scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
    395   if (!capturer.get())
    396     return -1;
    397 
    398   *samples_per_sec = static_cast<uint32_t>(
    399       capturer->audio_parameters().sample_rate());
    400   return 0;
    401 }
    402 
    403 int32_t WebRtcAudioDeviceImpl::PlayoutSampleRate(
    404     uint32_t* samples_per_sec) const {
    405   *samples_per_sec = static_cast<uint32_t>(output_sample_rate());
    406   return 0;
    407 }
    408 
    409 bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) {
    410   DCHECK(thread_checker_.CalledOnValidThread());
    411   DCHECK(renderer);
    412 
    413   base::AutoLock auto_lock(lock_);
    414   if (renderer_.get())
    415     return false;
    416 
    417   if (!renderer->Initialize(this))
    418     return false;
    419 
    420   renderer_ = renderer;
    421   return true;
    422 }
    423 
    424 void WebRtcAudioDeviceImpl::AddAudioCapturer(
    425     const scoped_refptr<WebRtcAudioCapturer>& capturer) {
    426   DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()";
    427   DCHECK(thread_checker_.CalledOnValidThread());
    428   DCHECK(capturer.get());
    429 
    430   // We only support one microphone today, which means the list can contain
    431   // only one capturer with a valid device id.
    432   DCHECK(capturer->device_id().empty() || !GetDefaultCapturer());
    433   base::AutoLock auto_lock(lock_);
    434   capturers_.push_back(capturer);
    435 }
    436 
    437 scoped_refptr<WebRtcAudioCapturer>
    438 WebRtcAudioDeviceImpl::GetDefaultCapturer() const {
    439   base::AutoLock auto_lock(lock_);
    440   for (CapturerList::const_iterator iter = capturers_.begin();
    441        iter != capturers_.end(); ++iter) {
    442     if (!(*iter)->device_id().empty())
    443       return *iter;
    444   }
    445 
    446   return NULL;
    447 }
    448 
    449 }  // namespace content
    450