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 29 matching lines...) Expand all Loading... |
40 } | 40 } |
41 | 41 |
42 private: | 42 private: |
43 base::Lock& lock_; | 43 base::Lock& lock_; |
44 const bool acquired_; | 44 const bool acquired_; |
45 DISALLOW_COPY_AND_ASSIGN(AutoTryLock); | 45 DISALLOW_COPY_AND_ASSIGN(AutoTryLock); |
46 }; | 46 }; |
47 | 47 |
48 } // namespace | 48 } // namespace |
49 | 49 |
| 50 // TeeFilter is a RenderCallback implementation that allows for a client to get |
| 51 // a copy of the data being rendered by the |renderer_| on Render(). This class |
| 52 // also holds to the necessary audio parameters. |
| 53 class WebAudioSourceProviderImpl::TeeFilter |
| 54 : public AudioRendererSink::RenderCallback { |
| 55 public: |
| 56 TeeFilter(AudioRendererSink::RenderCallback* renderer, |
| 57 int channels, |
| 58 int sample_rate) |
| 59 : renderer_(renderer), channels_(channels), sample_rate_(sample_rate) { |
| 60 DCHECK(renderer_); |
| 61 } |
| 62 ~TeeFilter() override {} |
| 63 |
| 64 // AudioRendererSink::RenderCallback implementation. |
| 65 // These are forwarders to |renderer_| and are here to allow for a client to |
| 66 // get a copy of the rendered audio by SetCopyAudioCallback(). |
| 67 int Render(AudioBus* audio_bus, |
| 68 uint32_t delay_milliseconds, |
| 69 uint32_t frames_skipped) override; |
| 70 void OnRenderError() override; |
| 71 |
| 72 int channels() const { return channels_; } |
| 73 int sample_rate() const { return sample_rate_; } |
| 74 void set_copy_audio_bus_callback( |
| 75 const WebAudioSourceProviderImpl::CopyAudioCB& callback) { |
| 76 copy_audio_bus_callback_ = callback; |
| 77 } |
| 78 |
| 79 private: |
| 80 AudioRendererSink::RenderCallback* const renderer_; |
| 81 const int channels_; |
| 82 const int sample_rate_; |
| 83 |
| 84 WebAudioSourceProviderImpl::CopyAudioCB copy_audio_bus_callback_; |
| 85 |
| 86 DISALLOW_COPY_AND_ASSIGN(TeeFilter); |
| 87 }; |
| 88 |
50 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl( | 89 WebAudioSourceProviderImpl::WebAudioSourceProviderImpl( |
51 const scoped_refptr<RestartableAudioRendererSink>& sink) | 90 const scoped_refptr<RestartableAudioRendererSink>& sink) |
52 : channels_(0), | 91 : volume_(1.0), |
53 sample_rate_(0), | |
54 volume_(1.0), | |
55 state_(kStopped), | 92 state_(kStopped), |
56 renderer_(NULL), | 93 client_(nullptr), |
57 client_(NULL), | |
58 sink_(sink), | 94 sink_(sink), |
59 weak_factory_(this) {} | 95 weak_factory_(this) {} |
60 | 96 |
61 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() { | 97 WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() { |
62 } | 98 } |
63 | 99 |
64 void WebAudioSourceProviderImpl::setClient( | 100 void WebAudioSourceProviderImpl::setClient( |
65 blink::WebAudioSourceProviderClient* client) { | 101 blink::WebAudioSourceProviderClient* client) { |
66 base::AutoLock auto_lock(sink_lock_); | 102 base::AutoLock auto_lock(sink_lock_); |
67 if (client && client != client_) { | 103 if (client && client != client_) { |
68 // Detach the audio renderer from normal playback. | 104 // Detach the audio renderer from normal playback. |
69 sink_->Stop(); | 105 sink_->Stop(); |
70 | 106 |
71 // The client will now take control by calling provideInput() periodically. | 107 // The client will now take control by calling provideInput() periodically. |
72 client_ = client; | 108 client_ = client; |
73 | 109 |
74 set_format_cb_ = BindToCurrentLoop(base::Bind( | 110 set_format_cb_ = BindToCurrentLoop(base::Bind( |
75 &WebAudioSourceProviderImpl::OnSetFormat, weak_factory_.GetWeakPtr())); | 111 &WebAudioSourceProviderImpl::OnSetFormat, weak_factory_.GetWeakPtr())); |
76 | 112 |
77 // If |renderer_| is set, then run |set_format_cb_| to send |client_| | 113 // If |tee_filter_| is set, it means we have been Initialize()d - then run |
78 // the current format info. If |renderer_| is not set, then |set_format_cb_| | 114 // |set_format_cb_| to send |client_| the current format info. Otherwise |
79 // will get called when Initialize() is called. | 115 // |set_format_cb_| will get called when Initialize() is called. |
80 // Note: Always using |set_format_cb_| ensures we have the same | 116 // Note: Always using |set_format_cb_| ensures we have the same locking |
81 // locking order when calling into |client_|. | 117 // order when calling into |client_|. |
82 if (renderer_) | 118 if (tee_filter_) |
83 base::ResetAndReturn(&set_format_cb_).Run(); | 119 base::ResetAndReturn(&set_format_cb_).Run(); |
84 } else if (!client && client_) { | 120 } else if (!client && client_) { |
85 // Restore normal playback. | 121 // Restore normal playback. |
86 client_ = NULL; | 122 client_ = nullptr; |
87 sink_->SetVolume(volume_); | 123 sink_->SetVolume(volume_); |
88 if (state_ >= kStarted) | 124 if (state_ >= kStarted) |
89 sink_->Start(); | 125 sink_->Start(); |
90 if (state_ >= kPlaying) | 126 if (state_ >= kPlaying) |
91 sink_->Play(); | 127 sink_->Play(); |
92 } | 128 } |
93 } | 129 } |
94 | 130 |
95 void WebAudioSourceProviderImpl::provideInput( | 131 void WebAudioSourceProviderImpl::provideInput( |
96 const WebVector<float*>& audio_data, size_t number_of_frames) { | 132 const WebVector<float*>& audio_data, size_t number_of_frames) { |
97 if (!bus_wrapper_ || | 133 if (!bus_wrapper_ || |
98 static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) { | 134 static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) { |
99 bus_wrapper_ = AudioBus::CreateWrapper(static_cast<int>(audio_data.size())); | 135 bus_wrapper_ = AudioBus::CreateWrapper(static_cast<int>(audio_data.size())); |
100 } | 136 } |
101 | 137 |
102 bus_wrapper_->set_frames(static_cast<int>(number_of_frames)); | 138 const int incoming_number_of_frames = static_cast<int>(number_of_frames); |
| 139 bus_wrapper_->set_frames(incoming_number_of_frames); |
103 for (size_t i = 0; i < audio_data.size(); ++i) | 140 for (size_t i = 0; i < audio_data.size(); ++i) |
104 bus_wrapper_->SetChannelData(static_cast<int>(i), audio_data[i]); | 141 bus_wrapper_->SetChannelData(static_cast<int>(i), audio_data[i]); |
105 | 142 |
106 // Use a try lock to avoid contention in the real-time audio thread. | 143 // Use a try lock to avoid contention in the real-time audio thread. |
107 AutoTryLock auto_try_lock(sink_lock_); | 144 AutoTryLock auto_try_lock(sink_lock_); |
108 if (!auto_try_lock.locked() || state_ != kPlaying) { | 145 if (!auto_try_lock.locked() || state_ != kPlaying) { |
109 // Provide silence if we failed to acquire the lock or the source is not | 146 // Provide silence if we failed to acquire the lock or the source is not |
110 // running. | 147 // running. |
111 bus_wrapper_->Zero(); | 148 bus_wrapper_->Zero(); |
112 return; | 149 return; |
113 } | 150 } |
114 | 151 |
115 DCHECK(renderer_); | |
116 DCHECK(client_); | 152 DCHECK(client_); |
117 DCHECK_EQ(channels_, bus_wrapper_->channels()); | 153 DCHECK(tee_filter_); |
118 const int frames = renderer_->Render(bus_wrapper_.get(), 0, 0); | 154 DCHECK_EQ(tee_filter_->channels(), bus_wrapper_->channels()); |
119 if (frames < static_cast<int>(number_of_frames)) { | 155 const int frames = tee_filter_->Render(bus_wrapper_.get(), 0, 0); |
120 bus_wrapper_->ZeroFramesPartial( | 156 if (frames < incoming_number_of_frames) |
121 frames, | 157 bus_wrapper_->ZeroFramesPartial(frames, incoming_number_of_frames - frames); |
122 static_cast<int>(number_of_frames - frames)); | |
123 } | |
124 | 158 |
125 bus_wrapper_->Scale(volume_); | 159 bus_wrapper_->Scale(volume_); |
126 } | 160 } |
127 | 161 |
128 void WebAudioSourceProviderImpl::Start() { | 162 void WebAudioSourceProviderImpl::Start() { |
129 base::AutoLock auto_lock(sink_lock_); | 163 base::AutoLock auto_lock(sink_lock_); |
130 DCHECK(renderer_); | 164 DCHECK(tee_filter_); |
131 DCHECK_EQ(state_, kStopped); | 165 DCHECK_EQ(state_, kStopped); |
132 state_ = kStarted; | 166 state_ = kStarted; |
133 if (!client_) | 167 if (!client_) |
134 sink_->Start(); | 168 sink_->Start(); |
135 } | 169 } |
136 | 170 |
137 void WebAudioSourceProviderImpl::Stop() { | 171 void WebAudioSourceProviderImpl::Stop() { |
138 base::AutoLock auto_lock(sink_lock_); | 172 base::AutoLock auto_lock(sink_lock_); |
139 state_ = kStopped; | 173 state_ = kStopped; |
140 if (!client_) | 174 if (!client_) |
(...skipping 22 matching lines...) Expand all Loading... |
163 if (!client_) | 197 if (!client_) |
164 sink_->SetVolume(volume); | 198 sink_->SetVolume(volume); |
165 return true; | 199 return true; |
166 } | 200 } |
167 | 201 |
168 OutputDevice* WebAudioSourceProviderImpl::GetOutputDevice() { | 202 OutputDevice* WebAudioSourceProviderImpl::GetOutputDevice() { |
169 base::AutoLock auto_lock(sink_lock_); | 203 base::AutoLock auto_lock(sink_lock_); |
170 return sink_->GetOutputDevice(); | 204 return sink_->GetOutputDevice(); |
171 } | 205 } |
172 | 206 |
173 void WebAudioSourceProviderImpl::Initialize( | 207 void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params, |
174 const AudioParameters& params, | 208 RenderCallback* renderer) { |
175 RenderCallback* renderer) { | |
176 base::AutoLock auto_lock(sink_lock_); | 209 base::AutoLock auto_lock(sink_lock_); |
177 renderer_ = renderer; | 210 DCHECK_EQ(state_, kStopped); |
178 | 211 |
179 DCHECK_EQ(state_, kStopped); | 212 tee_filter_ = make_scoped_ptr( |
180 sink_->Initialize(params, renderer); | 213 new TeeFilter(renderer, params.channels(), params.sample_rate())); |
181 | 214 |
182 // Keep track of the format in case the client hasn't yet been set. | 215 sink_->Initialize(params, tee_filter_.get()); |
183 channels_ = params.channels(); | |
184 sample_rate_ = params.sample_rate(); | |
185 | 216 |
186 if (!set_format_cb_.is_null()) | 217 if (!set_format_cb_.is_null()) |
187 base::ResetAndReturn(&set_format_cb_).Run(); | 218 base::ResetAndReturn(&set_format_cb_).Run(); |
188 } | 219 } |
189 | 220 |
| 221 void WebAudioSourceProviderImpl::SetCopyAudioCallback( |
| 222 const CopyAudioCB& callback) { |
| 223 DCHECK(!callback.is_null()); |
| 224 DCHECK(tee_filter_); |
| 225 tee_filter_->set_copy_audio_bus_callback(callback); |
| 226 } |
| 227 |
| 228 void WebAudioSourceProviderImpl::ClearCopyAudioCallback() { |
| 229 DCHECK(tee_filter_); |
| 230 tee_filter_->set_copy_audio_bus_callback(CopyAudioCB()); |
| 231 } |
| 232 |
190 void WebAudioSourceProviderImpl::OnSetFormat() { | 233 void WebAudioSourceProviderImpl::OnSetFormat() { |
191 base::AutoLock auto_lock(sink_lock_); | 234 base::AutoLock auto_lock(sink_lock_); |
192 if (!client_) | 235 if (!client_) |
193 return; | 236 return; |
194 | 237 |
195 // Inform Blink about the audio stream format. | 238 // Inform Blink about the audio stream format. |
196 client_->setFormat(channels_, sample_rate_); | 239 client_->setFormat(tee_filter_->channels(), tee_filter_->sample_rate()); |
| 240 } |
| 241 |
| 242 int WebAudioSourceProviderImpl::RenderForTesting(AudioBus* audio_bus) { |
| 243 return tee_filter_->Render(audio_bus, 0, 0); |
| 244 } |
| 245 |
| 246 int WebAudioSourceProviderImpl::TeeFilter::Render(AudioBus* audio_bus, |
| 247 uint32_t delay_milliseconds, |
| 248 uint32_t frames_skipped) { |
| 249 const int num_rendered_frames = |
| 250 renderer_->Render(audio_bus, delay_milliseconds, frames_skipped); |
| 251 |
| 252 if (!copy_audio_bus_callback_.is_null()) { |
| 253 scoped_ptr<AudioBus> bus_copy = |
| 254 AudioBus::Create(audio_bus->channels(), audio_bus->frames()); |
| 255 audio_bus->CopyTo(bus_copy.get()); |
| 256 copy_audio_bus_callback_.Run(std::move(bus_copy), delay_milliseconds, |
| 257 sample_rate_); |
| 258 } |
| 259 |
| 260 return num_rendered_frames; |
| 261 } |
| 262 |
| 263 void WebAudioSourceProviderImpl::TeeFilter::OnRenderError() { |
| 264 renderer_->OnRenderError(); |
197 } | 265 } |
198 | 266 |
199 } // namespace media | 267 } // namespace media |
OLD | NEW |