| 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/audio_renderer_impl.h" | |
| 6 | |
| 7 #include <math.h> | |
| 8 | |
| 9 #include <algorithm> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "content/common/child_process.h" | |
| 13 #include "content/common/media/audio_messages.h" | |
| 14 #include "content/renderer/media/audio_hardware.h" | |
| 15 #include "content/renderer/render_thread_impl.h" | |
| 16 #include "media/audio/audio_buffers_state.h" | |
| 17 #include "media/audio/audio_util.h" | |
| 18 #include "media/base/filter_host.h" | |
| 19 | |
| 20 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) | |
| 21 : AudioRendererBase(), | |
| 22 bytes_per_second_(0), | |
| 23 stopped_(false), | |
| 24 sink_(sink), | |
| 25 is_initialized_(false) { | |
| 26 } | |
| 27 | |
| 28 AudioRendererImpl::~AudioRendererImpl() { | |
| 29 } | |
| 30 | |
| 31 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { | |
| 32 if (bytes_per_second_) { | |
| 33 return base::TimeDelta::FromMicroseconds( | |
| 34 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); | |
| 35 } | |
| 36 return base::TimeDelta(); | |
| 37 } | |
| 38 | |
| 39 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled, | |
| 40 base::TimeDelta request_delay, | |
| 41 base::Time time_now) { | |
| 42 if (bytes_filled != 0) { | |
| 43 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled); | |
| 44 float playback_rate = GetPlaybackRate(); | |
| 45 if (playback_rate != 1.0f) { | |
| 46 predicted_play_time = base::TimeDelta::FromMicroseconds( | |
| 47 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * | |
| 48 playback_rate))); | |
| 49 } | |
| 50 earliest_end_time_ = | |
| 51 std::max(earliest_end_time_, | |
| 52 time_now + request_delay + predicted_play_time); | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 bool AudioRendererImpl::OnInitialize(int bits_per_channel, | |
| 57 ChannelLayout channel_layout, | |
| 58 int sample_rate) { | |
| 59 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY | |
| 60 // does not currently support all the sample-rates that we require. | |
| 61 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 | |
| 62 // for more details. | |
| 63 audio_parameters_.Reset( | |
| 64 media::AudioParameters::AUDIO_PCM_LINEAR, | |
| 65 channel_layout, sample_rate, bits_per_channel, | |
| 66 audio_hardware::GetHighLatencyOutputBufferSize(sample_rate)); | |
| 67 | |
| 68 bytes_per_second_ = audio_parameters_.GetBytesPerSecond(); | |
| 69 | |
| 70 DCHECK(sink_.get()); | |
| 71 | |
| 72 if (!is_initialized_) { | |
| 73 sink_->Initialize(audio_parameters_, this); | |
| 74 | |
| 75 sink_->Start(); | |
| 76 is_initialized_ = true; | |
| 77 return true; | |
| 78 } | |
| 79 | |
| 80 return false; | |
| 81 } | |
| 82 | |
| 83 void AudioRendererImpl::OnStop() { | |
| 84 if (stopped_) | |
| 85 return; | |
| 86 | |
| 87 DCHECK(sink_.get()); | |
| 88 sink_->Stop(); | |
| 89 | |
| 90 stopped_ = true; | |
| 91 } | |
| 92 | |
| 93 void AudioRendererImpl::SetPlaybackRate(float rate) { | |
| 94 DCHECK_LE(0.0f, rate); | |
| 95 | |
| 96 // Handle the case where we stopped due to IO message loop dying. | |
| 97 if (stopped_) { | |
| 98 AudioRendererBase::SetPlaybackRate(rate); | |
| 99 return; | |
| 100 } | |
| 101 | |
| 102 // We have two cases here: | |
| 103 // Play: GetPlaybackRate() == 0.0 && rate != 0.0 | |
| 104 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0 | |
| 105 if (GetPlaybackRate() == 0.0f && rate != 0.0f) { | |
| 106 DoPlay(); | |
| 107 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) { | |
| 108 // Pause is easy, we can always pause. | |
| 109 DoPause(); | |
| 110 } | |
| 111 AudioRendererBase::SetPlaybackRate(rate); | |
| 112 } | |
| 113 | |
| 114 void AudioRendererImpl::Pause(const base::Closure& callback) { | |
| 115 AudioRendererBase::Pause(callback); | |
| 116 if (stopped_) | |
| 117 return; | |
| 118 | |
| 119 DoPause(); | |
| 120 } | |
| 121 | |
| 122 void AudioRendererImpl::Seek(base::TimeDelta time, | |
| 123 const media::PipelineStatusCB& cb) { | |
| 124 AudioRendererBase::Seek(time, cb); | |
| 125 if (stopped_) | |
| 126 return; | |
| 127 | |
| 128 DoSeek(); | |
| 129 } | |
| 130 | |
| 131 void AudioRendererImpl::Play(const base::Closure& callback) { | |
| 132 AudioRendererBase::Play(callback); | |
| 133 if (stopped_) | |
| 134 return; | |
| 135 | |
| 136 if (GetPlaybackRate() != 0.0f) { | |
| 137 DoPlay(); | |
| 138 } else { | |
| 139 DoPause(); | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 void AudioRendererImpl::SetVolume(float volume) { | |
| 144 if (stopped_) | |
| 145 return; | |
| 146 DCHECK(sink_.get()); | |
| 147 sink_->SetVolume(volume); | |
| 148 } | |
| 149 | |
| 150 void AudioRendererImpl::DoPlay() { | |
| 151 earliest_end_time_ = base::Time::Now(); | |
| 152 DCHECK(sink_.get()); | |
| 153 sink_->Play(); | |
| 154 } | |
| 155 | |
| 156 void AudioRendererImpl::DoPause() { | |
| 157 DCHECK(sink_.get()); | |
| 158 sink_->Pause(false); | |
| 159 } | |
| 160 | |
| 161 void AudioRendererImpl::DoSeek() { | |
| 162 earliest_end_time_ = base::Time::Now(); | |
| 163 | |
| 164 // Pause and flush the stream when we seek to a new location. | |
| 165 DCHECK(sink_.get()); | |
| 166 sink_->Pause(true); | |
| 167 } | |
| 168 | |
| 169 size_t AudioRendererImpl::Render(const std::vector<float*>& audio_data, | |
| 170 size_t number_of_frames, | |
| 171 size_t audio_delay_milliseconds) { | |
| 172 if (stopped_ || GetPlaybackRate() == 0.0f) { | |
| 173 // Output silence if stopped. | |
| 174 for (size_t i = 0; i < audio_data.size(); ++i) | |
| 175 memset(audio_data[i], 0, sizeof(float) * number_of_frames); | |
| 176 return 0; | |
| 177 } | |
| 178 | |
| 179 // Adjust the playback delay. | |
| 180 base::TimeDelta request_delay = | |
| 181 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); | |
| 182 | |
| 183 // Finally we need to adjust the delay according to playback rate. | |
| 184 if (GetPlaybackRate() != 1.0f) { | |
| 185 request_delay = base::TimeDelta::FromMicroseconds( | |
| 186 static_cast<int64>(ceil(request_delay.InMicroseconds() * | |
| 187 GetPlaybackRate()))); | |
| 188 } | |
| 189 | |
| 190 int bytes_per_frame = audio_parameters_.GetBytesPerFrame(); | |
| 191 | |
| 192 const size_t buf_size = number_of_frames * bytes_per_frame; | |
| 193 scoped_array<uint8> buf(new uint8[buf_size]); | |
| 194 | |
| 195 uint32 frames_filled = FillBuffer(buf.get(), number_of_frames, request_delay); | |
| 196 uint32 bytes_filled = frames_filled * bytes_per_frame; | |
| 197 DCHECK_LE(bytes_filled, buf_size); | |
| 198 UpdateEarliestEndTime(bytes_filled, request_delay, base::Time::Now()); | |
| 199 | |
| 200 // Deinterleave each audio channel. | |
| 201 int channels = audio_data.size(); | |
| 202 for (int channel_index = 0; channel_index < channels; ++channel_index) { | |
| 203 media::DeinterleaveAudioChannel(buf.get(), | |
| 204 audio_data[channel_index], | |
| 205 channels, | |
| 206 channel_index, | |
| 207 bytes_per_frame / channels, | |
| 208 frames_filled); | |
| 209 | |
| 210 // If FillBuffer() didn't give us enough data then zero out the remainder. | |
| 211 if (frames_filled < number_of_frames) { | |
| 212 int frames_to_zero = number_of_frames - frames_filled; | |
| 213 memset(audio_data[channel_index] + frames_filled, | |
| 214 0, | |
| 215 sizeof(float) * frames_to_zero); | |
| 216 } | |
| 217 } | |
| 218 return frames_filled; | |
| 219 } | |
| 220 | |
| 221 void AudioRendererImpl::OnRenderError() { | |
| 222 host()->DisableAudioRenderer(); | |
| 223 } | |
| 224 | |
| 225 void AudioRendererImpl::OnRenderEndOfStream() { | |
| 226 // TODO(enal): schedule callback instead of polling. | |
| 227 if (base::Time::Now() >= earliest_end_time_) | |
| 228 SignalEndOfStream(); | |
| 229 } | |
| OLD | NEW |