Index: content/renderer/media/webaudio_media_stream_source.cc |
diff --git a/content/renderer/media/webaudio_media_stream_source.cc b/content/renderer/media/webaudio_media_stream_source.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..efdd7ed8364a269276d318e5f8bf1c9553fd855e |
--- /dev/null |
+++ b/content/renderer/media/webaudio_media_stream_source.cc |
@@ -0,0 +1,109 @@ |
+// Copyright (c) 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/webaudio_media_stream_source.h" |
+ |
+#include "base/bind.h" |
+#include "base/bind_helpers.h" |
+#include "base/logging.h" |
+ |
+namespace content { |
+ |
+WebAudioMediaStreamSource::WebAudioMediaStreamSource( |
+ const blink::WebMediaStreamSource& blink_source) |
+ : MediaStreamAudioSource(false /* is_remote */), |
+ blink_source_(blink_source), |
+ is_started_(false), |
+ rechunker_(base::TimeDelta::FromMilliseconds(10), |
+ base::Bind(&WebAudioMediaStreamSource::DeliverRechunkedAudio, |
+ base::Unretained(this))) { |
+ DVLOG(1) << "WebAudioMediaStreamSource::WebAudioMediaStreamSource()"; |
+} |
+ |
+WebAudioMediaStreamSource::~WebAudioMediaStreamSource() { |
+ DVLOG(1) << "WebAudioMediaStreamSource::~WebAudioMediaStreamSource()"; |
+ // Superclass will call StopSource() just in case. |
+} |
+ |
+void WebAudioMediaStreamSource::setFormat( |
+ size_t number_of_channels, float sample_rate) { |
+ VLOG(1) << "WebAudio media stream source changed format to: channels=" |
+ << number_of_channels << ", sample_rate=" << sample_rate; |
+ |
+ rechunker_.SetSampleRate(sample_rate); |
+ if (!wrapper_bus_ || |
+ wrapper_bus_->channels() != static_cast<int>(number_of_channels)) { |
+ wrapper_bus_ = media::AudioBus::CreateWrapper(number_of_channels); |
+ } |
+ |
+ // If the channel count is greater than 8, use discrete layout. However, |
+ // anything beyond 8 is ignored by some audio tracks/sinks. |
+ const media::ChannelLayout channel_layout = |
+ number_of_channels > 8 ? media::CHANNEL_LAYOUT_DISCRETE |
+ : media::GuessChannelLayout(number_of_channels); |
+ |
+ MediaStreamAudioSource::SetFormat(media::AudioParameters( |
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
+ channel_layout, |
+ sample_rate, |
+ 16, // Legacy parameter (data is always in 32-bit float format). |
+ rechunker_.output_frames())); |
+} |
+ |
+void WebAudioMediaStreamSource::consumeAudio( |
+ const blink::WebVector<const float*>& audio_data, |
+ size_t number_of_frames) { |
+ // TODO(miu): Plumbing is needed to determine the actual capture timestamp |
+ // of the audio, instead of just snapshotting TimeTicks::Now(), for proper |
+ // audio/video sync. http://crbug.com/335335 |
+ base::TimeTicks reference_time = base::TimeTicks::Now(); |
+ |
+ wrapper_bus_->set_frames(number_of_frames); |
+ DCHECK_EQ(wrapper_bus_->channels(), static_cast<int>(audio_data.size())); |
+ for (size_t i = 0; i < audio_data.size(); ++i) |
+ wrapper_bus_->SetChannelData(i, const_cast<float*>(audio_data[i])); |
+ |
+ rechunker_.Push(*wrapper_bus_, reference_time - base::TimeTicks()); |
+} |
+ |
+void WebAudioMediaStreamSource::DeliverRechunkedAudio( |
+ const media::AudioBus& audio_bus, |
+ base::TimeDelta reference_timestamp) { |
+ MediaStreamAudioSource::DeliverDataToTracks( |
+ audio_bus, reference_timestamp + base::TimeTicks()); |
+} |
+ |
+void WebAudioMediaStreamSource::DoStopSource() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ if (is_stopped_) |
+ return; |
+ if (is_started_) { |
+ if (!blink_source_.isNull()) { |
+ blink_source_.removeAudioConsumer(this); |
+ blink_source_.reset(); |
+ VLOG(1) << "Stopped WebAudio media stream source. Final audio " |
+ "parameters={" |
+ << GetAudioParameters().AsHumanReadableString() << "}."; |
+ } |
+ } |
+ is_stopped_ = true; |
+} |
+ |
+bool WebAudioMediaStreamSource::EnsureSourceIsStarted() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ if (is_stopped_) |
+ return false; |
+ if (is_started_) |
+ return true; |
+ if (blink_source_.isNull() || !blink_source_.requiresAudioConsumer()) { |
+ StopSource(); |
+ return false; |
+ } |
+ VLOG(1) << "Starting WebAudio media stream source."; |
+ blink_source_.addAudioConsumer(this); |
+ is_started_ = true; |
+ return true; |
+} |
+ |
+} // namespace content |