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