Index: content/renderer/media/html_audio_element_capturer_source.cc |
diff --git a/content/renderer/media/html_audio_element_capturer_source.cc b/content/renderer/media/html_audio_element_capturer_source.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..95a08f07eb3e260812872b36680de5215e001318 |
--- /dev/null |
+++ b/content/renderer/media/html_audio_element_capturer_source.cc |
@@ -0,0 +1,154 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/renderer/media/html_audio_element_capturer_source.h" |
+ |
+#include "base/threading/thread_task_runner_handle.h" |
+#include "base/timer/elapsed_timer.h" |
miu
2016/05/13 23:40:35
Seems this is not used.
mcasas
2016/05/14 02:23:47
Done.
|
+#include "media/base/audio_fifo.h" |
+#include "media/base/audio_parameters.h" |
+#include "media/base/audio_renderer_sink.h" |
+#include "media/blink/webmediaplayer_impl.h" |
+#include "third_party/WebKit/public/platform/WebMediaPlayer.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+// Maximum amount of buffers that can be held in the AudioFifo. |
+static const size_t kMaxNumberOfBuffers = 10; |
miu
2016/05/13 23:40:35
This can be deleted if you agree w/ my advice abou
mcasas
2016/05/14 02:23:47
Done.
|
+ |
+} // anonymous namespace |
+ |
+//static |
+scoped_refptr<HtmlAudioElementCapturerSource> |
+HtmlAudioElementCapturerSource::CreateFromWebMediaPlayerImpl( |
+ blink::WebMediaPlayer* player) { |
+ DCHECK(player); |
+ return make_scoped_refptr(new HtmlAudioElementCapturerSource( |
+ static_cast<media::WebAudioSourceProviderImpl*>( |
+ player->getAudioSourceProvider()) |
+ ->AsWeakPtr())); |
+} |
+ |
+HtmlAudioElementCapturerSource::HtmlAudioElementCapturerSource( |
+ const base::WeakPtr<media::WebAudioSourceProviderImpl>& audio_source) |
+ : audio_input_cb_( |
+ base::Bind(&HtmlAudioElementCapturerSource::OnAudioBus, this)), |
+ audio_source_(audio_source), |
+ min_fifo_frames_for_conversion_(0) { |
+ DCHECK(audio_source_); |
+} |
+ |
+void HtmlAudioElementCapturerSource::Initialize( |
+ const media::AudioParameters& params, |
+ CaptureCallback* callback, |
+ int session_id) { |
+ DVLOG(1) << __FUNCTION__ << params.AsHumanReadableString(); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ capture_callback_ = callback; |
+ output_params_ = params; |
+} |
+ |
+void HtmlAudioElementCapturerSource::Start() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ if (audio_source_) |
+ audio_source_->SetCopyAudioCallback(audio_input_cb_); |
miu
2016/05/13 23:40:35
By creating the closure in the ctor, HtmlAudioElem
mcasas
2016/05/14 02:23:47
Absolutely! Done.
|
+} |
+ |
+void HtmlAudioElementCapturerSource::Stop() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ if (audio_source_) |
+ audio_source_->ClearCopyAudioCallback(); |
+ capture_callback_ = nullptr; |
+} |
+ |
+void HtmlAudioElementCapturerSource::SetVolume(double volume) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void HtmlAudioElementCapturerSource::SetAutomaticGainControl(bool enable) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void HtmlAudioElementCapturerSource::OnAudioBus( |
+ std::unique_ptr<media::AudioBus> audio_bus, |
+ uint32_t delay_milliseconds, |
+ int sample_rate) { |
+ // Create |converter_| on first frame arrival. |
+ // TODO(mcasas): What if the input parameters change? |
+ if (!converter_) { |
+ // This parameter signifies the minimum input frames to produce a successful |
+ // conversion, and is usually smaller than |audio_bus.frames()|. We use it |
+ // to pull one by one converted AudioBuses out of AudioConverter. |
+ min_fifo_frames_for_conversion_ = output_params_.frames_per_buffer() * |
+ sample_rate / |
+ output_params_.sample_rate(); |
+ |
+ input_params_ = media::AudioParameters( |
+ output_params_.format(), |
+ media::GuessChannelLayout(audio_bus->channels()), sample_rate, |
+ output_params_.bits_per_sample(), min_fifo_frames_for_conversion_); |
+ DCHECK(input_params_.IsValid()); |
+ |
+ CreateConverter(); |
+ } |
+ DCHECK_EQ(input_params_.channels(), audio_bus->channels()); |
+ |
+ fifo_->Push(audio_bus.get()); |
miu
2016/05/13 23:40:35
All this code from here to the end of this method
mcasas
2016/05/14 02:23:47
Done.
|
+ |
+ // Convert() while there are enough frames queued up in |fifo_| to guarantee a |
+ // satisfactory conversion and retrieval of an output buffer, i.e. there are |
+ // at least |min_fifo_frames_for_conversion_|. |
+ const int input_block_size = audio_bus->frames(); |
+ while (fifo_->frames() >= min_fifo_frames_for_conversion_) { |
+ // Calculated the delay for Capture() based on the position of the converted |
+ // frames in the input buffer. Frequently there are frames left over from a |
+ // previous |audio_bus| and this delay will be negative. |
+ const int output_block_delay = (input_block_size - fifo_->frames()) * |
+ base::Time::kMillisecondsPerSecond / |
+ input_params_.sample_rate(); |
+ |
+ std::unique_ptr<media::AudioBus> converted_bus = media::AudioBus::Create( |
+ output_params_.channels(), output_params_.frames_per_buffer()); |
+ converter_->Convert(converted_bus.get()); |
+ |
+ // TODO(mcasas): The conversion process might take some time that might need |
+ // to be discounted: if that's the case, add a base::ElapsedTimer before |
+ // Convert() and subtract the Elapsed() time. |
+ DVLOG(3) << __FUNCTION__; |
+ capture_callback_->Capture(converted_bus.get(), output_block_delay, |
+ 1.0 /* volume */, false /* key_pressed */); |
+ } |
+} |
+ |
+double HtmlAudioElementCapturerSource::ProvideInput( |
+ media::AudioBus* audio_bus, |
+ base::TimeDelta buffer_delay) { |
+ DCHECK_EQ(min_fifo_frames_for_conversion_, audio_bus->frames()); |
+ fifo_->Consume(audio_bus, 0, audio_bus->frames()); |
+ return 1.0; // Return volume greater than zero to indicate we have more data. |
+} |
+ |
+HtmlAudioElementCapturerSource::~HtmlAudioElementCapturerSource() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void HtmlAudioElementCapturerSource::CreateConverter() { |
+ DCHECK(output_params_.IsValid()); |
+ DVLOG(1) << " Converting from: " << input_params_.AsHumanReadableString() |
+ << " --> " << output_params_.AsHumanReadableString(); |
+ |
+ converter_.reset(new media::AudioConverter(input_params_, output_params_, |
+ false /* disable_fifo */)); |
+ converter_->AddInput(this); |
+ converter_->PrimeWithSilence(); |
+ |
+ fifo_.reset(new media::AudioFifo( |
+ input_params_.channels(), |
+ kMaxNumberOfBuffers * input_params_.frames_per_buffer())); |
+} |
+ |
+} // namespace content |