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