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

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

Issue 2003963003: Reland: MediaCaptureFromElement: add support for audio captureStream(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: WASPImpl can be initialized after HTMLAudioElementCapturerSource Created 4 years, 7 months 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"
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
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()) // ???
DaleCurtis 2016/05/23 18:37:18 Remove ???
mcasas 2016/05/23 19:00:13 Done.
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
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
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 if (!renderer_)
DaleCurtis 2016/05/23 18:37:18 This should be impossible, no?
mcasas 2016/05/23 19:00:13 It could be possible if we get data before the |re
268 return 0;
269
261 const int num_rendered_frames = 270 const int num_rendered_frames =
262 renderer_->Render(audio_bus, delay_milliseconds, frames_skipped); 271 renderer_->Render(audio_bus, delay_milliseconds, frames_skipped);
263 272
264 if (!copy_audio_bus_callback_.is_null()) { 273 if (!copy_audio_bus_callback_.is_null()) {
265 std::unique_ptr<AudioBus> bus_copy = 274 std::unique_ptr<AudioBus> bus_copy =
266 AudioBus::Create(audio_bus->channels(), audio_bus->frames()); 275 AudioBus::Create(audio_bus->channels(), audio_bus->frames());
267 audio_bus->CopyTo(bus_copy.get()); 276 audio_bus->CopyTo(bus_copy.get());
268 copy_audio_bus_callback_.Run(std::move(bus_copy), delay_milliseconds, 277 copy_audio_bus_callback_.Run(std::move(bus_copy), delay_milliseconds,
269 sample_rate_); 278 sample_rate_);
270 } 279 }
271 280
272 return num_rendered_frames; 281 return num_rendered_frames;
273 } 282 }
274 283
275 void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() { 284 void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() {
276 renderer_->OnRenderError(); 285 if (renderer_)
DaleCurtis 2016/05/23 18:37:18 Ditto.
mcasas 2016/05/23 19:00:13 Acknowledged.
286 renderer_->OnRenderError();
277 } 287 }
278 288
279 } // namespace media 289 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698