| 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" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 private: | 43 private: |
| 44 base::Lock& lock_; | 44 base::Lock& lock_; |
| 45 const bool acquired_; | 45 const bool acquired_; |
| 46 DISALLOW_COPY_AND_ASSIGN(AutoTryLock); | 46 DISALLOW_COPY_AND_ASSIGN(AutoTryLock); |
| 47 }; | 47 }; |
| 48 | 48 |
| 49 } // namespace | 49 } // namespace |
| 50 | 50 |
| 51 // TeeFilter is a RenderCallback implementation that allows for a client to get | 51 // TeeFilter is a RenderCallback implementation that allows for a client to get |
| 52 // a copy of the data being rendered by the |renderer_| on Render(). This class | 52 // a copy of the data being rendered by the |renderer_| on Render(). This class |
| 53 // also holds to the necessary audio parameters. | 53 // also holds on to the necessary audio parameters. |
| 54 class WebAudioSourceProviderImpl::TeeFilter | 54 class WebAudioSourceProviderImpl::TeeFilter |
| 55 : public AudioRendererSink::RenderCallback { | 55 : public AudioRendererSink::RenderCallback { |
| 56 public: | 56 public: |
| 57 TeeFilter(AudioRendererSink::RenderCallback* renderer, | 57 TeeFilter() : renderer_(nullptr), channels_(0), sample_rate_(0) {} |
| 58 int channels, | 58 ~TeeFilter() override {} |
| 59 int sample_rate) | 59 |
| 60 : renderer_(renderer), channels_(channels), sample_rate_(sample_rate) { | 60 void Initialize(AudioRendererSink::RenderCallback* renderer, |
| 61 DCHECK(renderer_); | 61 int channels, |
| 62 int sample_rate) { |
| 63 DCHECK(renderer); |
| 64 renderer_ = renderer; |
| 65 channels_ = channels; |
| 66 sample_rate_ = sample_rate; |
| 62 } | 67 } |
| 63 ~TeeFilter() override {} | |
| 64 | 68 |
| 65 // AudioRendererSink::RenderCallback implementation. | 69 // AudioRendererSink::RenderCallback implementation. |
| 66 // These are forwarders to |renderer_| and are here to allow for a client to | 70 // These are forwarders to |renderer_| and are here to allow for a client to |
| 67 // get a copy of the rendered audio by SetCopyAudioCallback(). | 71 // get a copy of the rendered audio by SetCopyAudioCallback(). |
| 68 int Render(AudioBus* audio_bus, | 72 int Render(AudioBus* audio_bus, |
| 69 uint32_t delay_milliseconds, | 73 uint32_t delay_milliseconds, |
| 70 uint32_t frames_skipped) override; | 74 uint32_t frames_skipped) override; |
| 71 void OnRenderError() override; | 75 void OnRenderError() override; |
| 72 | 76 |
| 77 bool IsInitialized() const { return !!renderer_; } |
| 73 int channels() const { return channels_; } | 78 int channels() const { return channels_; } |
| 74 int sample_rate() const { return sample_rate_; } | 79 int sample_rate() const { return sample_rate_; } |
| 75 void set_copy_audio_bus_callback( | 80 void set_copy_audio_bus_callback(const CopyAudioCB& callback) { |
| 76 const WebAudioSourceProviderImpl::CopyAudioCB& callback) { | |
| 77 copy_audio_bus_callback_ = callback; | 81 copy_audio_bus_callback_ = callback; |
| 78 } | 82 } |
| 79 | 83 |
| 80 private: | 84 private: |
| 81 AudioRendererSink::RenderCallback* const renderer_; | 85 AudioRendererSink::RenderCallback* renderer_; |
| 82 const int channels_; | 86 int channels_; |
| 83 const int sample_rate_; | 87 int sample_rate_; |
| 84 | 88 |
| 85 WebAudioSourceProviderImpl::CopyAudioCB copy_audio_bus_callback_; | 89 CopyAudioCB copy_audio_bus_callback_; |
| 86 | 90 |
| 87 DISALLOW_COPY_AND_ASSIGN(TeeFilter); | 91 DISALLOW_COPY_AND_ASSIGN(TeeFilter); |
| 88 }; | 92 }; |
| 89 | 93 |
| 90 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl( | 94 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl( |
| 91 const scoped_refptr<SwitchableAudioRendererSink>& sink) | 95 const scoped_refptr<SwitchableAudioRendererSink>& sink) |
| 92 : volume_(1.0), | 96 : volume_(1.0), |
| 93 state_(kStopped), | 97 state_(kStopped), |
| 94 client_(nullptr), | 98 client_(nullptr), |
| 95 sink_(sink), | 99 sink_(sink), |
| 100 tee_filter_(new TeeFilter()), |
| 96 weak_factory_(this) {} | 101 weak_factory_(this) {} |
| 97 | 102 |
| 98 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() { | 103 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() { |
| 99 } | 104 } |
| 100 | 105 |
| 101 void WebAudioSourceProviderImpl::setClient( | 106 void WebAudioSourceProviderImpl::setClient( |
| 102 blink::WebAudioSourceProviderClient* client) { | 107 blink::WebAudioSourceProviderClient* client) { |
| 103 base::AutoLock auto_lock(sink_lock_); | 108 base::AutoLock auto_lock(sink_lock_); |
| 104 if (client && client != client_) { | 109 if (client && client != client_) { |
| 105 // Detach the audio renderer from normal playback. | 110 // Detach the audio renderer from normal playback. |
| 106 sink_->Stop(); | 111 sink_->Stop(); |
| 107 | 112 |
| 108 // The client will now take control by calling provideInput() periodically. | 113 // The client will now take control by calling provideInput() periodically. |
| 109 client_ = client; | 114 client_ = client; |
| 110 | 115 |
| 111 set_format_cb_ = BindToCurrentLoop(base::Bind( | 116 set_format_cb_ = BindToCurrentLoop(base::Bind( |
| 112 &WebAudioSourceProviderImpl::OnSetFormat, weak_factory_.GetWeakPtr())); | 117 &WebAudioSourceProviderImpl::OnSetFormat, weak_factory_.GetWeakPtr())); |
| 113 | 118 |
| 114 // If |tee_filter_| is set, it means we have been Initialize()d - then run | 119 // If |tee_filter_| is Initialize()d - then run |set_format_cb_| to send |
| 115 // |set_format_cb_| to send |client_| the current format info. Otherwise | 120 // |client_| the current format info. Otherwise |set_format_cb_| will get |
| 116 // |set_format_cb_| will get called when Initialize() is called. | 121 // called when Initialize() is called. Note: Always using |set_format_cb_| |
| 117 // Note: Always using |set_format_cb_| ensures we have the same locking | 122 // ensures we have the same locking order when calling into |client_|. |
| 118 // order when calling into |client_|. | 123 if (tee_filter_->IsInitialized()) |
| 119 if (tee_filter_) | |
| 120 base::ResetAndReturn(&set_format_cb_).Run(); | 124 base::ResetAndReturn(&set_format_cb_).Run(); |
| 121 } else if (!client && client_) { | 125 } else if (!client && client_) { |
| 122 // Restore normal playback. | 126 // Restore normal playback. |
| 123 client_ = nullptr; | 127 client_ = nullptr; |
| 124 sink_->SetVolume(volume_); | 128 sink_->SetVolume(volume_); |
| 125 if (state_ >= kStarted) | 129 if (state_ >= kStarted) |
| 126 sink_->Start(); | 130 sink_->Start(); |
| 127 if (state_ >= kPlaying) | 131 if (state_ >= kPlaying) |
| 128 sink_->Play(); | 132 sink_->Play(); |
| 129 } | 133 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 144 // Use a try lock to avoid contention in the real-time audio thread. | 148 // Use a try lock to avoid contention in the real-time audio thread. |
| 145 AutoTryLock auto_try_lock(sink_lock_); | 149 AutoTryLock auto_try_lock(sink_lock_); |
| 146 if (!auto_try_lock.locked() || state_ != kPlaying) { | 150 if (!auto_try_lock.locked() || state_ != kPlaying) { |
| 147 // Provide silence if we failed to acquire the lock or the source is not | 151 // Provide silence if we failed to acquire the lock or the source is not |
| 148 // running. | 152 // running. |
| 149 bus_wrapper_->Zero(); | 153 bus_wrapper_->Zero(); |
| 150 return; | 154 return; |
| 151 } | 155 } |
| 152 | 156 |
| 153 DCHECK(client_); | 157 DCHECK(client_); |
| 154 DCHECK(tee_filter_); | |
| 155 DCHECK_EQ(tee_filter_->channels(), bus_wrapper_->channels()); | 158 DCHECK_EQ(tee_filter_->channels(), bus_wrapper_->channels()); |
| 156 const int frames = tee_filter_->Render(bus_wrapper_.get(), 0, 0); | 159 const int frames = tee_filter_->Render(bus_wrapper_.get(), 0, 0); |
| 157 if (frames < incoming_number_of_frames) | 160 if (frames < incoming_number_of_frames) |
| 158 bus_wrapper_->ZeroFramesPartial(frames, incoming_number_of_frames - frames); | 161 bus_wrapper_->ZeroFramesPartial(frames, incoming_number_of_frames - frames); |
| 159 | 162 |
| 160 bus_wrapper_->Scale(volume_); | 163 bus_wrapper_->Scale(volume_); |
| 161 } | 164 } |
| 162 | 165 |
| 163 void WebAudioSourceProviderImpl::Start() { | 166 void WebAudioSourceProviderImpl::Start() { |
| 164 base::AutoLock auto_lock(sink_lock_); | 167 base::AutoLock auto_lock(sink_lock_); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 callback.Run(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); | 217 callback.Run(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); |
| 215 else | 218 else |
| 216 sink_->SwitchOutputDevice(device_id, security_origin, callback); | 219 sink_->SwitchOutputDevice(device_id, security_origin, callback); |
| 217 } | 220 } |
| 218 | 221 |
| 219 void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params, | 222 void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params, |
| 220 RenderCallback* renderer) { | 223 RenderCallback* renderer) { |
| 221 base::AutoLock auto_lock(sink_lock_); | 224 base::AutoLock auto_lock(sink_lock_); |
| 222 DCHECK_EQ(state_, kStopped); | 225 DCHECK_EQ(state_, kStopped); |
| 223 | 226 |
| 224 tee_filter_ = base::WrapUnique( | 227 tee_filter_->Initialize(renderer, params.channels(), params.sample_rate()); |
| 225 new TeeFilter(renderer, params.channels(), params.sample_rate())); | |
| 226 | 228 |
| 227 sink_->Initialize(params, tee_filter_.get()); | 229 sink_->Initialize(params, tee_filter_.get()); |
| 228 | 230 |
| 229 if (!set_format_cb_.is_null()) | 231 if (!set_format_cb_.is_null()) |
| 230 base::ResetAndReturn(&set_format_cb_).Run(); | 232 base::ResetAndReturn(&set_format_cb_).Run(); |
| 231 } | 233 } |
| 232 | 234 |
| 233 void WebAudioSourceProviderImpl::SetCopyAudioCallback( | 235 void WebAudioSourceProviderImpl::SetCopyAudioCallback( |
| 234 const CopyAudioCB& callback) { | 236 const CopyAudioCB& callback) { |
| 235 DCHECK(!callback.is_null()); | 237 DCHECK(!callback.is_null()); |
| 238 |
| 239 // Use |sink_lock_| to protect |tee_filter_| too since they go in lockstep. |
| 240 base::AutoLock auto_lock(sink_lock_); |
| 241 |
| 236 DCHECK(tee_filter_); | 242 DCHECK(tee_filter_); |
| 237 tee_filter_->set_copy_audio_bus_callback(callback); | 243 tee_filter_->set_copy_audio_bus_callback(callback); |
| 238 } | 244 } |
| 239 | 245 |
| 240 void WebAudioSourceProviderImpl::ClearCopyAudioCallback() { | 246 void WebAudioSourceProviderImpl::ClearCopyAudioCallback() { |
| 241 DCHECK(tee_filter_); | 247 DCHECK(tee_filter_); |
| 242 tee_filter_->set_copy_audio_bus_callback(CopyAudioCB()); | 248 tee_filter_->set_copy_audio_bus_callback(CopyAudioCB()); |
| 243 } | 249 } |
| 244 | 250 |
| 251 int WebAudioSourceProviderImpl::RenderForTesting(AudioBus* audio_bus) { |
| 252 return tee_filter_->Render(audio_bus, 0, 0); |
| 253 } |
| 254 |
| 245 void WebAudioSourceProviderImpl::OnSetFormat() { | 255 void WebAudioSourceProviderImpl::OnSetFormat() { |
| 246 base::AutoLock auto_lock(sink_lock_); | 256 base::AutoLock auto_lock(sink_lock_); |
| 247 if (!client_) | 257 if (!client_) |
| 248 return; | 258 return; |
| 249 | 259 |
| 250 // Inform Blink about the audio stream format. | 260 // Inform Blink about the audio stream format. |
| 251 client_->setFormat(tee_filter_->channels(), tee_filter_->sample_rate()); | 261 client_->setFormat(tee_filter_->channels(), tee_filter_->sample_rate()); |
| 252 } | 262 } |
| 253 | 263 |
| 254 int WebAudioSourceProviderImpl::RenderForTesting(AudioBus* audio_bus) { | |
| 255 return tee_filter_->Render(audio_bus, 0, 0); | |
| 256 } | |
| 257 | |
| 258 int WebAudioSourceProviderImpl::TeeFilter::Render(AudioBus* audio_bus, | 264 int WebAudioSourceProviderImpl::TeeFilter::Render(AudioBus* audio_bus, |
| 259 uint32_t delay_milliseconds, | 265 uint32_t delay_milliseconds, |
| 260 uint32_t frames_skipped) { | 266 uint32_t frames_skipped) { |
| 267 DCHECK(IsInitialized()); |
| 268 |
| 261 const int num_rendered_frames = | 269 const int num_rendered_frames = |
| 262 renderer_->Render(audio_bus, delay_milliseconds, frames_skipped); | 270 renderer_->Render(audio_bus, delay_milliseconds, frames_skipped); |
| 263 | 271 |
| 264 if (!copy_audio_bus_callback_.is_null()) { | 272 if (!copy_audio_bus_callback_.is_null()) { |
| 265 std::unique_ptr<AudioBus> bus_copy = | 273 std::unique_ptr<AudioBus> bus_copy = |
| 266 AudioBus::Create(audio_bus->channels(), audio_bus->frames()); | 274 AudioBus::Create(audio_bus->channels(), audio_bus->frames()); |
| 267 audio_bus->CopyTo(bus_copy.get()); | 275 audio_bus->CopyTo(bus_copy.get()); |
| 268 copy_audio_bus_callback_.Run(std::move(bus_copy), delay_milliseconds, | 276 copy_audio_bus_callback_.Run(std::move(bus_copy), delay_milliseconds, |
| 269 sample_rate_); | 277 sample_rate_); |
| 270 } | 278 } |
| 271 | 279 |
| 272 return num_rendered_frames; | 280 return num_rendered_frames; |
| 273 } | 281 } |
| 274 | 282 |
| 275 void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() { | 283 void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() { |
| 284 DCHECK(IsInitialized()); |
| 276 renderer_->OnRenderError(); | 285 renderer_->OnRenderError(); |
| 277 } | 286 } |
| 278 | 287 |
| 279 } // namespace media | 288 } // namespace media |
| OLD | NEW |