Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / webaudiosourceprovider_impl.cc
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/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 content {
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:
28   explicit AutoTryLock(base::Lock& lock)
29       : lock_(lock),
30         acquired_(lock_.Try()) {}
31
32   bool locked() const { return acquired_; }
33
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
49 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl(
50     const scoped_refptr<media::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
60 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() {
61 }
62
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_ = media::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
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_ = media::AudioBus::CreateWrapper(audio_data.size());
99   }
100
101   bus_wrapper_->set_frames(number_of_frames);
102   for (size_t i = 0; i < audio_data.size(); ++i)
103     bus_wrapper_->SetChannelData(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 size_t frames = renderer_->Render(bus_wrapper_.get(), 0);
118   if (frames < number_of_frames)
119     bus_wrapper_->ZeroFramesPartial(frames, number_of_frames - frames);
120   bus_wrapper_->Scale(volume_);
121 }
122
123 void WebAudioSourceProviderImpl::Start() {
124   base::AutoLock auto_lock(sink_lock_);
125   DCHECK_EQ(state_, kStopped);
126   state_ = kStarted;
127   if (!client_)
128     sink_->Start();
129 }
130
131 void WebAudioSourceProviderImpl::Stop() {
132   base::AutoLock auto_lock(sink_lock_);
133   state_ = kStopped;
134   if (!client_)
135     sink_->Stop();
136 }
137
138 void WebAudioSourceProviderImpl::Play() {
139   base::AutoLock auto_lock(sink_lock_);
140   DCHECK_EQ(state_, kStarted);
141   state_ = kPlaying;
142   if (!client_)
143     sink_->Play();
144 }
145
146 void WebAudioSourceProviderImpl::Pause() {
147   base::AutoLock auto_lock(sink_lock_);
148   DCHECK(state_ == kPlaying || state_ == kStarted);
149   state_ = kStarted;
150   if (!client_)
151     sink_->Pause();
152 }
153
154 bool WebAudioSourceProviderImpl::SetVolume(double volume) {
155   base::AutoLock auto_lock(sink_lock_);
156   volume_ = volume;
157   if (!client_)
158     sink_->SetVolume(volume);
159   return true;
160 }
161
162 void WebAudioSourceProviderImpl::Initialize(
163     const media::AudioParameters& params,
164     RenderCallback* renderer) {
165   base::AutoLock auto_lock(sink_lock_);
166   CHECK(!renderer_);
167   renderer_ = renderer;
168
169   DCHECK_EQ(state_, kStopped);
170   sink_->Initialize(params, renderer);
171
172   // Keep track of the format in case the client hasn't yet been set.
173   channels_ = params.channels();
174   sample_rate_ = params.sample_rate();
175
176   if (!set_format_cb_.is_null())
177     base::ResetAndReturn(&set_format_cb_).Run();
178 }
179
180 void WebAudioSourceProviderImpl::OnSetFormat() {
181   base::AutoLock auto_lock(sink_lock_);
182   if (!client_)
183     return;
184
185   // Inform Blink about the audio stream format.
186   client_->setFormat(channels_, sample_rate_);
187 }
188
189 }  // namespace content