| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |