| 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 |