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 |