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/webaudiosourceprovider_impl.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/logging.h"
     10 #include "third_party/WebKit/public/web/WebAudioSourceProviderClient.h"
     11 
     12 using WebKit::WebVector;
     13 
     14 namespace content {
     15 
     16 namespace {
     17 
     18 // Simple helper class for Try() locks.  Lock is Try()'d on construction and
     19 // must be checked via the locked() attribute.  If acquisition was successful
     20 // the lock will be released upon destruction.
     21 // TODO(dalecurtis): This should probably move to base/ if others start using
     22 // this pattern.
     23 class AutoTryLock {
     24  public:
     25   explicit AutoTryLock(base::Lock& lock)
     26       : lock_(lock),
     27         acquired_(lock_.Try()) {}
     28 
     29   bool locked() const { return acquired_; }
     30 
     31   ~AutoTryLock() {
     32     if (acquired_) {
     33       lock_.AssertAcquired();
     34       lock_.Release();
     35     }
     36   }
     37 
     38  private:
     39   base::Lock& lock_;
     40   const bool acquired_;
     41   DISALLOW_COPY_AND_ASSIGN(AutoTryLock);
     42 };
     43 
     44 }  // namespace
     45 
     46 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl(
     47     const scoped_refptr<media::AudioRendererSink>& sink)
     48     : channels_(0),
     49       sample_rate_(0),
     50       volume_(1.0),
     51       state_(kStopped),
     52       renderer_(NULL),
     53       client_(NULL),
     54       sink_(sink) {
     55 }
     56 
     57 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() {}
     58 
     59 void WebAudioSourceProviderImpl::setClient(
     60     WebKit::WebAudioSourceProviderClient* client) {
     61   base::AutoLock auto_lock(sink_lock_);
     62   if (client && client != client_) {
     63     // Detach the audio renderer from normal playback.
     64     sink_->Stop();
     65 
     66     // The client will now take control by calling provideInput() periodically.
     67     client_ = client;
     68 
     69     if (renderer_) {
     70       // The client needs to be notified of the audio format, if available.
     71       // If the format is not yet available, we'll be notified later
     72       // when Initialize() is called.
     73 
     74       // Inform WebKit about the audio stream format.
     75       client->setFormat(channels_, sample_rate_);
     76     }
     77   } else if (!client && client_) {
     78     // Restore normal playback.
     79     client_ = NULL;
     80     sink_->SetVolume(volume_);
     81     if (state_ >= kStarted)
     82       sink_->Start();
     83     if (state_ >= kPlaying)
     84       sink_->Play();
     85   }
     86 }
     87 
     88 void WebAudioSourceProviderImpl::provideInput(
     89     const WebVector<float*>& audio_data, size_t number_of_frames) {
     90   if (!bus_wrapper_ ||
     91       static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) {
     92     bus_wrapper_ = media::AudioBus::CreateWrapper(audio_data.size());
     93   }
     94 
     95   bus_wrapper_->set_frames(number_of_frames);
     96   for (size_t i = 0; i < audio_data.size(); ++i)
     97     bus_wrapper_->SetChannelData(i, audio_data[i]);
     98 
     99   // Use a try lock to avoid contention in the real-time audio thread.
    100   AutoTryLock auto_try_lock(sink_lock_);
    101   if (!auto_try_lock.locked() || state_ != kPlaying) {
    102     // Provide silence if we failed to acquire the lock or the source is not
    103     // running.
    104     bus_wrapper_->Zero();
    105     return;
    106   }
    107 
    108   DCHECK(renderer_);
    109   DCHECK(client_);
    110   DCHECK_EQ(channels_, bus_wrapper_->channels());
    111   renderer_->Render(bus_wrapper_.get(), 0);
    112   bus_wrapper_->Scale(volume_);
    113 }
    114 
    115 void WebAudioSourceProviderImpl::Start() {
    116   base::AutoLock auto_lock(sink_lock_);
    117   DCHECK_EQ(state_, kStopped);
    118   state_ = kStarted;
    119   if (!client_)
    120     sink_->Start();
    121 }
    122 
    123 void WebAudioSourceProviderImpl::Stop() {
    124   base::AutoLock auto_lock(sink_lock_);
    125   state_ = kStopped;
    126   if (!client_)
    127     sink_->Stop();
    128 }
    129 
    130 void WebAudioSourceProviderImpl::Play() {
    131   base::AutoLock auto_lock(sink_lock_);
    132   DCHECK_EQ(state_, kStarted);
    133   state_ = kPlaying;
    134   if (!client_)
    135     sink_->Play();
    136 }
    137 
    138 void WebAudioSourceProviderImpl::Pause() {
    139   base::AutoLock auto_lock(sink_lock_);
    140   DCHECK(state_ == kPlaying || state_ == kStarted);
    141   state_ = kStarted;
    142   if (!client_)
    143     sink_->Pause();
    144 }
    145 
    146 bool WebAudioSourceProviderImpl::SetVolume(double volume) {
    147   base::AutoLock auto_lock(sink_lock_);
    148   volume_ = volume;
    149   if (!client_)
    150     sink_->SetVolume(volume);
    151   return true;
    152 }
    153 
    154 void WebAudioSourceProviderImpl::Initialize(
    155     const media::AudioParameters& params,
    156     RenderCallback* renderer) {
    157   base::AutoLock auto_lock(sink_lock_);
    158   CHECK(!renderer_);
    159   renderer_ = renderer;
    160 
    161   DCHECK_EQ(state_, kStopped);
    162   sink_->Initialize(params, renderer);
    163 
    164   // Keep track of the format in case the client hasn't yet been set.
    165   channels_ = params.channels();
    166   sample_rate_ = params.sample_rate();
    167 
    168   if (client_) {
    169     // Inform WebKit about the audio stream format.
    170     client_->setFormat(channels_, sample_rate_);
    171   }
    172 }
    173 
    174 }  // namespace content
    175