| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/renderer/media/webaudio_media_stream_source.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/bind_helpers.h" | |
| 9 #include "base/logging.h" | |
| 10 | |
| 11 namespace content { | |
| 12 | |
| 13 WebAudioMediaStreamSource::WebAudioMediaStreamSource( | |
| 14 blink::WebMediaStreamSource* blink_source) | |
| 15 : MediaStreamAudioSource(false /* is_remote */), | |
| 16 is_registered_consumer_(false), | |
| 17 fifo_(base::Bind(&WebAudioMediaStreamSource::DeliverRebufferedAudio, | |
| 18 base::Unretained(this))), | |
| 19 blink_source_(*blink_source) { | |
| 20 DVLOG(1) << "WebAudioMediaStreamSource::WebAudioMediaStreamSource()"; | |
| 21 } | |
| 22 | |
| 23 WebAudioMediaStreamSource::~WebAudioMediaStreamSource() { | |
| 24 DVLOG(1) << "WebAudioMediaStreamSource::~WebAudioMediaStreamSource()"; | |
| 25 EnsureSourceIsStopped(); | |
| 26 } | |
| 27 | |
| 28 void WebAudioMediaStreamSource::setFormat(size_t number_of_channels, | |
| 29 float sample_rate) { | |
| 30 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 31 VLOG(1) << "WebAudio media stream source changed format to: channels=" | |
| 32 << number_of_channels << ", sample_rate=" << sample_rate; | |
| 33 | |
| 34 // If the channel count is greater than 8, use discrete layout. However, | |
| 35 // anything beyond 8 is ignored by some audio tracks/sinks. | |
| 36 media::ChannelLayout channel_layout = | |
| 37 number_of_channels > 8 ? media::CHANNEL_LAYOUT_DISCRETE | |
| 38 : media::GuessChannelLayout(number_of_channels); | |
| 39 | |
| 40 // Set the format used by this WebAudioMediaStreamSource. We are using 10ms | |
| 41 // data as a buffer size since that is the native buffer size of WebRtc packet | |
| 42 // running on. | |
| 43 // | |
| 44 // TODO(miu): Re-evaluate whether this is needed. For now (this refactoring), | |
| 45 // I did not want to change behavior. http://crbug.com/577874 | |
| 46 fifo_.Reset(sample_rate / 100); | |
| 47 media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | |
| 48 channel_layout, sample_rate, 16, | |
| 49 fifo_.frames_per_buffer()); | |
| 50 // Take care of the discrete channel layout case. | |
| 51 params.set_channels_for_discrete(number_of_channels); | |
| 52 MediaStreamAudioSource::SetFormat(params); | |
| 53 | |
| 54 if (!wrapper_bus_ || wrapper_bus_->channels() != params.channels()) | |
| 55 wrapper_bus_ = media::AudioBus::CreateWrapper(params.channels()); | |
| 56 } | |
| 57 | |
| 58 bool WebAudioMediaStreamSource::EnsureSourceIsStarted() { | |
| 59 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 60 if (is_registered_consumer_) | |
| 61 return true; | |
| 62 if (blink_source_.isNull() || !blink_source_.requiresAudioConsumer()) | |
| 63 return false; | |
| 64 VLOG(1) << "Starting WebAudio media stream source."; | |
| 65 blink_source_.addAudioConsumer(this); | |
| 66 is_registered_consumer_ = true; | |
| 67 return true; | |
| 68 } | |
| 69 | |
| 70 void WebAudioMediaStreamSource::EnsureSourceIsStopped() { | |
| 71 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 72 if (!is_registered_consumer_) | |
| 73 return; | |
| 74 is_registered_consumer_ = false; | |
| 75 DCHECK(!blink_source_.isNull()); | |
| 76 blink_source_.removeAudioConsumer(this); | |
| 77 blink_source_.reset(); | |
| 78 VLOG(1) << "Stopped WebAudio media stream source. Final audio parameters={" | |
| 79 << GetAudioParameters().AsHumanReadableString() << "}."; | |
| 80 } | |
| 81 | |
| 82 void WebAudioMediaStreamSource::consumeAudio( | |
| 83 const blink::WebVector<const float*>& audio_data, | |
| 84 size_t number_of_frames) { | |
| 85 // TODO(miu): Plumbing is needed to determine the actual capture timestamp | |
| 86 // of the audio, instead of just snapshotting TimeTicks::Now(), for proper | |
| 87 // audio/video sync. http://crbug.com/335335 | |
| 88 current_reference_time_ = base::TimeTicks::Now(); | |
| 89 | |
| 90 wrapper_bus_->set_frames(number_of_frames); | |
| 91 DCHECK_EQ(wrapper_bus_->channels(), static_cast<int>(audio_data.size())); | |
| 92 for (size_t i = 0; i < audio_data.size(); ++i) | |
| 93 wrapper_bus_->SetChannelData(i, const_cast<float*>(audio_data[i])); | |
| 94 | |
| 95 // The following will result in zero, one, or multiple synchronous calls to | |
| 96 // DeliverRebufferedAudio(). | |
| 97 fifo_.Push(*wrapper_bus_); | |
| 98 } | |
| 99 | |
| 100 void WebAudioMediaStreamSource::DeliverRebufferedAudio( | |
| 101 const media::AudioBus& audio_bus, | |
| 102 int frame_delay) { | |
| 103 const base::TimeTicks reference_time = | |
| 104 current_reference_time_ + | |
| 105 base::TimeDelta::FromMicroseconds( | |
| 106 frame_delay * base::Time::kMicrosecondsPerSecond / | |
| 107 MediaStreamAudioSource::GetAudioParameters().sample_rate()); | |
| 108 MediaStreamAudioSource::DeliverDataToTracks(audio_bus, reference_time); | |
| 109 } | |
| 110 | |
| 111 } // namespace content | |
| OLD | NEW |