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

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

Issue 2569883003: Fallback to null sink moved from WebMediaPlayer to WebAudioSourceProvider::Initialize(), so that we… (Closed)
Patch Set: Created 4 years 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"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/single_thread_task_runner.h"
16 #include "media/audio/null_audio_sink.h"
17 #include "media/base/audio_timestamp_helper.h"
14 #include "media/base/bind_to_current_loop.h" 18 #include "media/base/bind_to_current_loop.h"
19 #include "media/base/media_log.h"
15 #include "third_party/WebKit/public/platform/WebAudioSourceProviderClient.h" 20 #include "third_party/WebKit/public/platform/WebAudioSourceProviderClient.h"
16 21
17 using blink::WebVector; 22 using blink::WebVector;
18 23
19 namespace media { 24 namespace media {
20 25
21 namespace { 26 namespace {
22 27
23 // Simple helper class for Try() locks. Lock is Try()'d on construction and 28 // Simple helper class for Try() locks. Lock is Try()'d on construction and
24 // must be checked via the locked() attribute. If acquisition was successful 29 // must be checked via the locked() attribute. If acquisition was successful
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 AudioRendererSink::RenderCallback* renderer_; 90 AudioRendererSink::RenderCallback* renderer_;
86 int channels_; 91 int channels_;
87 int sample_rate_; 92 int sample_rate_;
88 93
89 CopyAudioCB copy_audio_bus_callback_; 94 CopyAudioCB copy_audio_bus_callback_;
90 95
91 DISALLOW_COPY_AND_ASSIGN(TeeFilter); 96 DISALLOW_COPY_AND_ASSIGN(TeeFilter);
92 }; 97 };
93 98
94 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl( 99 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl(
95 const scoped_refptr<SwitchableAudioRendererSink>& sink) 100 scoped_refptr<SwitchableAudioRendererSink> sink,
101 scoped_refptr<MediaLog> media_log)
96 : volume_(1.0), 102 : volume_(1.0),
97 state_(kStopped), 103 state_(kStopped),
98 client_(nullptr), 104 client_(nullptr),
99 sink_(sink), 105 sink_(std::move(sink)),
100 tee_filter_(new TeeFilter()), 106 tee_filter_(new TeeFilter()),
107 media_log_(std::move(media_log)),
101 weak_factory_(this) {} 108 weak_factory_(this) {}
102 109
103 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() { 110 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() {
104 } 111 }
105 112
106 void WebAudioSourceProviderImpl::setClient( 113 void WebAudioSourceProviderImpl::setClient(
107 blink::WebAudioSourceProviderClient* client) { 114 blink::WebAudioSourceProviderClient* client) {
108 // Skip taking the lock if unnecessary. This function is the only setter for 115 // Skip taking the lock if unnecessary. This function is the only setter for
109 // |client_| so it's safe to check |client_| outside of the lock. 116 // |client_| so it's safe to check |client_| outside of the lock.
110 if (client_ == client) 117 if (client_ == client)
111 return; 118 return;
112 119
113 base::AutoLock auto_lock(sink_lock_); 120 base::AutoLock auto_lock(sink_lock_);
114 if (client) { 121 if (client) {
115 // Detach the audio renderer from normal playback. 122 // Detach the audio renderer from normal playback.
116 sink_->Stop(); 123 if (sink_)
124 sink_->Stop();
117 125
118 // The client will now take control by calling provideInput() periodically. 126 // The client will now take control by calling provideInput() periodically.
119 client_ = client; 127 client_ = client;
120 128
121 set_format_cb_ = BindToCurrentLoop(base::Bind( 129 set_format_cb_ = BindToCurrentLoop(base::Bind(
122 &WebAudioSourceProviderImpl::OnSetFormat, weak_factory_.GetWeakPtr())); 130 &WebAudioSourceProviderImpl::OnSetFormat, weak_factory_.GetWeakPtr()));
123 131
124 // If |tee_filter_| is Initialize()d - then run |set_format_cb_| to send 132 // If |tee_filter_| is Initialize()d - then run |set_format_cb_| to send
125 // |client_| the current format info. Otherwise |set_format_cb_| will get 133 // |client_| the current format info. Otherwise |set_format_cb_| will get
126 // called when Initialize() is called. Note: Always using |set_format_cb_| 134 // called when Initialize() is called. Note: Always using |set_format_cb_|
127 // ensures we have the same locking order when calling into |client_|. 135 // ensures we have the same locking order when calling into |client_|.
128 if (tee_filter_->IsInitialized()) 136 if (tee_filter_->IsInitialized())
129 base::ResetAndReturn(&set_format_cb_).Run(); 137 base::ResetAndReturn(&set_format_cb_).Run();
130 return; 138 return;
131 } 139 }
132 140
133 // Restore normal playback. 141 // Restore normal playback.
134 client_ = nullptr; 142 client_ = nullptr;
135 sink_->SetVolume(volume_); 143 if (sink_) {
136 if (state_ >= kStarted) 144 sink_->SetVolume(volume_);
137 sink_->Start(); 145 if (state_ >= kStarted)
138 if (state_ >= kPlaying) 146 sink_->Start();
139 sink_->Play(); 147 if (state_ >= kPlaying)
148 sink_->Play();
149 }
140 } 150 }
141 151
142 void WebAudioSourceProviderImpl::provideInput( 152 void WebAudioSourceProviderImpl::provideInput(
143 const WebVector<float*>& audio_data, size_t number_of_frames) { 153 const WebVector<float*>& audio_data, size_t number_of_frames) {
144 if (!bus_wrapper_ || 154 if (!bus_wrapper_ ||
145 static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) { 155 static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) {
146 bus_wrapper_ = AudioBus::CreateWrapper(static_cast<int>(audio_data.size())); 156 bus_wrapper_ = AudioBus::CreateWrapper(static_cast<int>(audio_data.size()));
147 } 157 }
148 158
149 const int incoming_number_of_frames = static_cast<int>(number_of_frames); 159 const int incoming_number_of_frames = static_cast<int>(number_of_frames);
(...skipping 17 matching lines...) Expand all
167 bus_wrapper_->ZeroFramesPartial(frames, incoming_number_of_frames - frames); 177 bus_wrapper_->ZeroFramesPartial(frames, incoming_number_of_frames - frames);
168 178
169 bus_wrapper_->Scale(volume_); 179 bus_wrapper_->Scale(volume_);
170 } 180 }
171 181
172 void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params, 182 void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params,
173 RenderCallback* renderer) { 183 RenderCallback* renderer) {
174 base::AutoLock auto_lock(sink_lock_); 184 base::AutoLock auto_lock(sink_lock_);
175 DCHECK_EQ(state_, kStopped); 185 DCHECK_EQ(state_, kStopped);
176 186
187 OutputDeviceStatus device_status =
188 sink_ ? sink_->GetOutputDeviceInfo().device_status()
189 : OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND;
190
191 UMA_HISTOGRAM_ENUMERATION("Media.WebAudioSourceProvider.SinkStatus",
192 device_status, OUTPUT_DEVICE_STATUS_MAX + 1);
193
194 if (device_status != OUTPUT_DEVICE_STATUS_OK) {
195 // Since null sink is always OK, we will fall back to it once and forever.
196 if (sink_)
197 sink_->Stop();
198 sink_ = CreateFallbackSink();
199 MEDIA_LOG(ERROR, media_log_)
200 << "Output device error, falling back to null sink";
201 }
202
177 tee_filter_->Initialize(renderer, params.channels(), params.sample_rate()); 203 tee_filter_->Initialize(renderer, params.channels(), params.sample_rate());
178 204
179 sink_->Initialize(params, tee_filter_.get()); 205 sink_->Initialize(params, tee_filter_.get());
180 206
181 if (!set_format_cb_.is_null()) 207 if (!set_format_cb_.is_null())
182 base::ResetAndReturn(&set_format_cb_).Run(); 208 base::ResetAndReturn(&set_format_cb_).Run();
183 } 209 }
184 210
185 void WebAudioSourceProviderImpl::Start() { 211 void WebAudioSourceProviderImpl::Start() {
186 base::AutoLock auto_lock(sink_lock_); 212 base::AutoLock auto_lock(sink_lock_);
(...skipping 23 matching lines...) Expand all
210 base::AutoLock auto_lock(sink_lock_); 236 base::AutoLock auto_lock(sink_lock_);
211 DCHECK(state_ == kPlaying || state_ == kStarted); 237 DCHECK(state_ == kPlaying || state_ == kStarted);
212 state_ = kStarted; 238 state_ = kStarted;
213 if (!client_) 239 if (!client_)
214 sink_->Pause(); 240 sink_->Pause();
215 } 241 }
216 242
217 bool WebAudioSourceProviderImpl::SetVolume(double volume) { 243 bool WebAudioSourceProviderImpl::SetVolume(double volume) {
218 base::AutoLock auto_lock(sink_lock_); 244 base::AutoLock auto_lock(sink_lock_);
219 volume_ = volume; 245 volume_ = volume;
220 if (!client_) 246 if (!client_ && sink_)
221 sink_->SetVolume(volume); 247 sink_->SetVolume(volume);
222 return true; 248 return true;
223 } 249 }
224 250
225 media::OutputDeviceInfo WebAudioSourceProviderImpl::GetOutputDeviceInfo() { 251 OutputDeviceInfo WebAudioSourceProviderImpl::GetOutputDeviceInfo() {
226 base::AutoLock auto_lock(sink_lock_); 252 base::AutoLock auto_lock(sink_lock_);
227 return sink_->GetOutputDeviceInfo(); 253 return sink_ ? sink_->GetOutputDeviceInfo()
254 : OutputDeviceInfo(OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND);
228 } 255 }
229 256
230 bool WebAudioSourceProviderImpl::CurrentThreadIsRenderingThread() { 257 bool WebAudioSourceProviderImpl::CurrentThreadIsRenderingThread() {
231 NOTIMPLEMENTED(); 258 NOTIMPLEMENTED();
232 return false; 259 return false;
233 } 260 }
234 261
235 void WebAudioSourceProviderImpl::SwitchOutputDevice( 262 void WebAudioSourceProviderImpl::SwitchOutputDevice(
236 const std::string& device_id, 263 const std::string& device_id,
237 const url::Origin& security_origin, 264 const url::Origin& security_origin,
238 const OutputDeviceStatusCB& callback) { 265 const OutputDeviceStatusCB& callback) {
239 base::AutoLock auto_lock(sink_lock_); 266 base::AutoLock auto_lock(sink_lock_);
240 if (client_) 267 if (client_ || !sink_)
241 callback.Run(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); 268 callback.Run(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
242 else 269 else
243 sink_->SwitchOutputDevice(device_id, security_origin, callback); 270 sink_->SwitchOutputDevice(device_id, security_origin, callback);
244 } 271 }
245 272
246 void WebAudioSourceProviderImpl::SetCopyAudioCallback( 273 void WebAudioSourceProviderImpl::SetCopyAudioCallback(
247 const CopyAudioCB& callback) { 274 const CopyAudioCB& callback) {
248 DCHECK(!callback.is_null()); 275 DCHECK(!callback.is_null());
249 276
250 // Use |sink_lock_| to protect |tee_filter_| too since they go in lockstep. 277 // Use |sink_lock_| to protect |tee_filter_| too since they go in lockstep.
251 base::AutoLock auto_lock(sink_lock_); 278 base::AutoLock auto_lock(sink_lock_);
(...skipping 13 matching lines...) Expand all
265 292
266 void WebAudioSourceProviderImpl::OnSetFormat() { 293 void WebAudioSourceProviderImpl::OnSetFormat() {
267 base::AutoLock auto_lock(sink_lock_); 294 base::AutoLock auto_lock(sink_lock_);
268 if (!client_) 295 if (!client_)
269 return; 296 return;
270 297
271 // Inform Blink about the audio stream format. 298 // Inform Blink about the audio stream format.
272 client_->setFormat(tee_filter_->channels(), tee_filter_->sample_rate()); 299 client_->setFormat(tee_filter_->channels(), tee_filter_->sample_rate());
273 } 300 }
274 301
302 scoped_refptr<SwitchableAudioRendererSink>
303 WebAudioSourceProviderImpl::CreateFallbackSink() {
304 // Assuming it is called on media thread.
305 return new NullAudioSink(base::ThreadTaskRunnerHandle::Get());
306 }
307
275 int WebAudioSourceProviderImpl::TeeFilter::Render(AudioBus* audio_bus, 308 int WebAudioSourceProviderImpl::TeeFilter::Render(AudioBus* audio_bus,
276 uint32_t frames_delayed, 309 uint32_t frames_delayed,
277 uint32_t frames_skipped) { 310 uint32_t frames_skipped) {
278 DCHECK(IsInitialized()); 311 DCHECK(IsInitialized());
279 312
280 const int num_rendered_frames = 313 const int num_rendered_frames =
281 renderer_->Render(audio_bus, frames_delayed, frames_skipped); 314 renderer_->Render(audio_bus, frames_delayed, frames_skipped);
282 315
283 if (!copy_audio_bus_callback_.is_null()) { 316 if (!copy_audio_bus_callback_.is_null()) {
284 std::unique_ptr<AudioBus> bus_copy = 317 std::unique_ptr<AudioBus> bus_copy =
285 AudioBus::Create(audio_bus->channels(), audio_bus->frames()); 318 AudioBus::Create(audio_bus->channels(), audio_bus->frames());
286 audio_bus->CopyTo(bus_copy.get()); 319 audio_bus->CopyTo(bus_copy.get());
287 copy_audio_bus_callback_.Run(std::move(bus_copy), frames_delayed, 320 copy_audio_bus_callback_.Run(std::move(bus_copy), frames_delayed,
288 sample_rate_); 321 sample_rate_);
289 } 322 }
290 323
291 return num_rendered_frames; 324 return num_rendered_frames;
292 } 325 }
293 326
294 void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() { 327 void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() {
295 DCHECK(IsInitialized()); 328 DCHECK(IsInitialized());
296 renderer_->OnRenderError(); 329 renderer_->OnRenderError();
297 } 330 }
298 331
299 } // namespace media 332 } // namespace media
OLDNEW
« no previous file with comments | « media/blink/webaudiosourceprovider_impl.h ('k') | media/blink/webaudiosourceprovider_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698