Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(269)

Side by Side Diff: media/blink/webaudiosourceprovider_impl.cc

Issue 1781043002: media::WebAudioSourceProviderImpl, add support for getting a copy of passing AudioBuses (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: dalecurtis@ comments Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/blink/webaudiosourceprovider_impl.h" 5 #include "media/blink/webaudiosourceprovider_impl.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback_helpers.h" 10 #include "base/callback_helpers.h"
(...skipping 29 matching lines...) Expand all
40 } 40 }
41 41
42 private: 42 private:
43 base::Lock& lock_; 43 base::Lock& lock_;
44 const bool acquired_; 44 const bool acquired_;
45 DISALLOW_COPY_AND_ASSIGN(AutoTryLock); 45 DISALLOW_COPY_AND_ASSIGN(AutoTryLock);
46 }; 46 };
47 47
48 } // namespace 48 } // namespace
49 49
50 // TeeFilter is a RenderCallback implementation that allows for a client to get
51 // a copy of the data being rendered by the |renderer_| on Render(). This class
52 // also holds to the necessary audio parameters.
53 class WebAudioSourceProviderImpl::TeeFilter
54 : public AudioRendererSink::RenderCallback {
55 public:
56 TeeFilter(AudioRendererSink::RenderCallback* const renderer,
DaleCurtis 2016/03/12 03:24:42 RenderCallback* const doesn't mean anything as a p
mcasas 2016/03/16 18:50:50 Done.
57 int channels,
58 int sample_rate)
59 : renderer_(renderer), channels_(channels), sample_rate_(sample_rate) {
60 DCHECK(renderer_);
61 }
62 ~TeeFilter() override {}
63
64 // AudioRendererSink::RenderCallback implementation.
65 // These are forwarders to |renderer_| and are here to allow for a client to
66 // get a copy of the rendered audio by RegisterCopyAudioCallback().
67 int Render(AudioBus* audio_bus,
68 uint32_t delay_milliseconds,
69 uint32_t frames_skipped) override;
70 void OnRenderError() override;
71
72 int channels() const { return channels_; }
73 int sample_rate() const { return sample_rate_; }
74 void set_copy_audio_bus_callback(
75 const WebAudioSourceProviderImpl::CopyAudioCB& callback) {
76 copy_audio_bus_callback_ = callback;
77 }
78
79 private:
80 AudioRendererSink::RenderCallback* const renderer_;
81 const int channels_;
82 const int sample_rate_;
83
84 WebAudioSourceProviderImpl::CopyAudioCB copy_audio_bus_callback_;
85
86 DISALLOW_COPY_AND_ASSIGN(TeeFilter);
87 };
88
50 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl( 89 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl(
51 const scoped_refptr<RestartableAudioRendererSink>& sink) 90 const scoped_refptr<RestartableAudioRendererSink>& sink)
52 : channels_(0), 91 : volume_(1.0),
53 sample_rate_(0),
54 volume_(1.0),
55 state_(kStopped), 92 state_(kStopped),
56 renderer_(NULL), 93 client_(nullptr),
57 client_(NULL),
58 sink_(sink), 94 sink_(sink),
59 weak_factory_(this) {} 95 weak_factory_(this) {}
60 96
61 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() { 97 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() {
62 } 98 }
63 99
64 void WebAudioSourceProviderImpl::setClient( 100 void WebAudioSourceProviderImpl::setClient(
65 blink::WebAudioSourceProviderClient* client) { 101 blink::WebAudioSourceProviderClient* client) {
66 base::AutoLock auto_lock(sink_lock_); 102 base::AutoLock auto_lock(sink_lock_);
67 if (client && client != client_) { 103 if (client && client != client_) {
68 // Detach the audio renderer from normal playback. 104 // Detach the audio renderer from normal playback.
69 sink_->Stop(); 105 sink_->Stop();
70 106
71 // The client will now take control by calling provideInput() periodically. 107 // The client will now take control by calling provideInput() periodically.
72 client_ = client; 108 client_ = client;
73 109
74 set_format_cb_ = BindToCurrentLoop(base::Bind( 110 set_format_cb_ = BindToCurrentLoop(base::Bind(
75 &WebAudioSourceProviderImpl::OnSetFormat, weak_factory_.GetWeakPtr())); 111 &WebAudioSourceProviderImpl::OnSetFormat, weak_factory_.GetWeakPtr()));
76 112
77 // If |renderer_| is set, then run |set_format_cb_| to send |client_| 113 // If |tee_filter_| is set, it means we have been Initialize()d - then run
78 // the current format info. If |renderer_| is not set, then |set_format_cb_| 114 // |set_format_cb_| to send |client_| the current format info. Otherwise
79 // will get called when Initialize() is called. 115 // |set_format_cb_| will get called when Initialize() is called.
80 // Note: Always using |set_format_cb_| ensures we have the same 116 // Note: Always using |set_format_cb_| ensures we have the same locking
81 // locking order when calling into |client_|. 117 // order when calling into |client_|.
82 if (renderer_) 118 if (tee_filter_)
83 base::ResetAndReturn(&set_format_cb_).Run(); 119 base::ResetAndReturn(&set_format_cb_).Run();
84 } else if (!client && client_) { 120 } else if (!client && client_) {
85 // Restore normal playback. 121 // Restore normal playback.
86 client_ = NULL; 122 client_ = nullptr;
87 sink_->SetVolume(volume_); 123 sink_->SetVolume(volume_);
88 if (state_ >= kStarted) 124 if (state_ >= kStarted)
89 sink_->Start(); 125 sink_->Start();
90 if (state_ >= kPlaying) 126 if (state_ >= kPlaying)
91 sink_->Play(); 127 sink_->Play();
92 } 128 }
93 } 129 }
94 130
95 void WebAudioSourceProviderImpl::provideInput( 131 void WebAudioSourceProviderImpl::provideInput(
96 const WebVector<float*>& audio_data, size_t number_of_frames) { 132 const WebVector<float*>& audio_data, size_t number_of_frames) {
97 if (!bus_wrapper_ || 133 if (!bus_wrapper_ ||
98 static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) { 134 static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) {
99 bus_wrapper_ = AudioBus::CreateWrapper(static_cast<int>(audio_data.size())); 135 bus_wrapper_ = AudioBus::CreateWrapper(static_cast<int>(audio_data.size()));
100 } 136 }
101 137
102 bus_wrapper_->set_frames(static_cast<int>(number_of_frames)); 138 const int incoming_number_of_frames = static_cast<int>(number_of_frames);
139 bus_wrapper_->set_frames(incoming_number_of_frames);
103 for (size_t i = 0; i < audio_data.size(); ++i) 140 for (size_t i = 0; i < audio_data.size(); ++i)
104 bus_wrapper_->SetChannelData(static_cast<int>(i), audio_data[i]); 141 bus_wrapper_->SetChannelData(static_cast<int>(i), audio_data[i]);
105 142
106 // Use a try lock to avoid contention in the real-time audio thread. 143 // Use a try lock to avoid contention in the real-time audio thread.
107 AutoTryLock auto_try_lock(sink_lock_); 144 AutoTryLock auto_try_lock(sink_lock_);
108 if (!auto_try_lock.locked() || state_ != kPlaying) { 145 if (!auto_try_lock.locked() || state_ != kPlaying) {
109 // Provide silence if we failed to acquire the lock or the source is not 146 // Provide silence if we failed to acquire the lock or the source is not
110 // running. 147 // running.
111 bus_wrapper_->Zero(); 148 bus_wrapper_->Zero();
112 return; 149 return;
113 } 150 }
114 151
115 DCHECK(renderer_);
116 DCHECK(client_); 152 DCHECK(client_);
117 DCHECK_EQ(channels_, bus_wrapper_->channels()); 153 DCHECK(tee_filter_);
118 const int frames = renderer_->Render(bus_wrapper_.get(), 0, 0); 154 DCHECK_EQ(tee_filter_->channels(), bus_wrapper_->channels());
119 if (frames < static_cast<int>(number_of_frames)) { 155 const int frames = tee_filter_->Render(bus_wrapper_.get(), 0, 0);
120 bus_wrapper_->ZeroFramesPartial( 156 if (frames < incoming_number_of_frames)
121 frames, 157 bus_wrapper_->ZeroFramesPartial(frames, incoming_number_of_frames - frames);
122 static_cast<int>(number_of_frames - frames));
123 }
124 158
125 bus_wrapper_->Scale(volume_); 159 bus_wrapper_->Scale(volume_);
126 } 160 }
127 161
128 void WebAudioSourceProviderImpl::Start() { 162 void WebAudioSourceProviderImpl::Start() {
129 base::AutoLock auto_lock(sink_lock_); 163 base::AutoLock auto_lock(sink_lock_);
130 DCHECK(renderer_); 164 DCHECK(tee_filter_);
131 DCHECK_EQ(state_, kStopped); 165 DCHECK_EQ(state_, kStopped);
132 state_ = kStarted; 166 state_ = kStarted;
133 if (!client_) 167 if (!client_)
134 sink_->Start(); 168 sink_->Start();
135 } 169 }
136 170
137 void WebAudioSourceProviderImpl::Stop() { 171 void WebAudioSourceProviderImpl::Stop() {
138 base::AutoLock auto_lock(sink_lock_); 172 base::AutoLock auto_lock(sink_lock_);
139 state_ = kStopped; 173 state_ = kStopped;
140 if (!client_) 174 if (!client_)
(...skipping 22 matching lines...) Expand all
163 if (!client_) 197 if (!client_)
164 sink_->SetVolume(volume); 198 sink_->SetVolume(volume);
165 return true; 199 return true;
166 } 200 }
167 201
168 OutputDevice* WebAudioSourceProviderImpl::GetOutputDevice() { 202 OutputDevice* WebAudioSourceProviderImpl::GetOutputDevice() {
169 base::AutoLock auto_lock(sink_lock_); 203 base::AutoLock auto_lock(sink_lock_);
170 return sink_->GetOutputDevice(); 204 return sink_->GetOutputDevice();
171 } 205 }
172 206
173 void WebAudioSourceProviderImpl::Initialize( 207 void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params,
174 const AudioParameters& params, 208 RenderCallback* renderer) {
175 RenderCallback* renderer) {
176 base::AutoLock auto_lock(sink_lock_); 209 base::AutoLock auto_lock(sink_lock_);
177 renderer_ = renderer; 210 DCHECK_EQ(state_, kStopped);
178 211
179 DCHECK_EQ(state_, kStopped); 212 tee_filter_ = make_scoped_ptr(
180 sink_->Initialize(params, renderer); 213 new TeeFilter(renderer, params.channels(), params.sample_rate()));
181 214
182 // Keep track of the format in case the client hasn't yet been set. 215 sink_->Initialize(params, tee_filter_.get());
183 channels_ = params.channels();
184 sample_rate_ = params.sample_rate();
185 216
186 if (!set_format_cb_.is_null()) 217 if (!set_format_cb_.is_null())
187 base::ResetAndReturn(&set_format_cb_).Run(); 218 base::ResetAndReturn(&set_format_cb_).Run();
188 } 219 }
189 220
221 void WebAudioSourceProviderImpl::RegisterCopyAudioCallback(
222 const CopyAudioCB& callback) {
223 DCHECK(!callback.is_null());
224 DCHECK(tee_filter_);
225 tee_filter_->set_copy_audio_bus_callback(callback);
226 }
227
228 void WebAudioSourceProviderImpl::ClearCopyAudioCallback() {
229 DCHECK(tee_filter_);
230 tee_filter_->set_copy_audio_bus_callback(CopyAudioCB());
231 }
232
190 void WebAudioSourceProviderImpl::OnSetFormat() { 233 void WebAudioSourceProviderImpl::OnSetFormat() {
191 base::AutoLock auto_lock(sink_lock_); 234 base::AutoLock auto_lock(sink_lock_);
192 if (!client_) 235 if (!client_)
193 return; 236 return;
194 237
195 // Inform Blink about the audio stream format. 238 // Inform Blink about the audio stream format.
196 client_->setFormat(channels_, sample_rate_); 239 client_->setFormat(tee_filter_->channels(), tee_filter_->sample_rate());
240 }
241
242 int WebAudioSourceProviderImpl::RenderForTesting(AudioBus* audio_bus) {
243 return tee_filter_->Render(audio_bus, 0, 0);
244 }
245
246 int WebAudioSourceProviderImpl::TeeFilter::Render(AudioBus* audio_bus,
247 uint32_t delay_milliseconds,
248 uint32_t frames_skipped) {
249 const int num_rendered_frames =
250 renderer_->Render(audio_bus, delay_milliseconds, frames_skipped);
251
252 if (!copy_audio_bus_callback_.is_null()) {
253 scoped_ptr<AudioBus> bus_copy =
254 AudioBus::Create(audio_bus->channels(), audio_bus->frames());
255 audio_bus->CopyTo(bus_copy.get());
256 copy_audio_bus_callback_.Run(std::move(bus_copy), delay_milliseconds,
257 sample_rate_);
258 }
259
260 return num_rendered_frames;
261 }
262
263 void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() {
264 renderer_->OnRenderError();
197 } 265 }
198 266
199 } // namespace media 267 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698