Move media/audio files into media namespace
[chromium-blink-merge.git] / content / renderer / media / audio_renderer_impl.cc
blob81d1cc6fae350f3933c62e8433d1e84292e1cdf5
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.
5 #include "content/renderer/media/audio_renderer_impl.h"
7 #include <math.h>
9 #include <algorithm>
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"
20 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink)
21 : AudioRendererBase(),
22 bytes_per_second_(0),
23 stopped_(false),
24 sink_(sink),
25 is_initialized_(false) {
28 AudioRendererImpl::~AudioRendererImpl() {
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_);
36 return base::TimeDelta();
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)));
50 earliest_end_time_ =
51 std::max(earliest_end_time_,
52 time_now + request_delay + predicted_play_time);
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));
68 bytes_per_second_ = audio_parameters_.GetBytesPerSecond();
70 DCHECK(sink_.get());
72 if (!is_initialized_) {
73 sink_->Initialize(audio_parameters_, this);
75 sink_->Start();
76 is_initialized_ = true;
77 return true;
80 return false;
83 void AudioRendererImpl::OnStop() {
84 if (stopped_)
85 return;
87 DCHECK(sink_.get());
88 sink_->Stop();
90 stopped_ = true;
93 void AudioRendererImpl::SetPlaybackRate(float rate) {
94 DCHECK_LE(0.0f, rate);
96 // Handle the case where we stopped due to IO message loop dying.
97 if (stopped_) {
98 AudioRendererBase::SetPlaybackRate(rate);
99 return;
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();
111 AudioRendererBase::SetPlaybackRate(rate);
114 void AudioRendererImpl::Pause(const base::Closure& callback) {
115 AudioRendererBase::Pause(callback);
116 if (stopped_)
117 return;
119 DoPause();
122 void AudioRendererImpl::Seek(base::TimeDelta time,
123 const media::PipelineStatusCB& cb) {
124 AudioRendererBase::Seek(time, cb);
125 if (stopped_)
126 return;
128 DoSeek();
131 void AudioRendererImpl::Play(const base::Closure& callback) {
132 AudioRendererBase::Play(callback);
133 if (stopped_)
134 return;
136 if (GetPlaybackRate() != 0.0f) {
137 DoPlay();
138 } else {
139 DoPause();
143 void AudioRendererImpl::SetVolume(float volume) {
144 if (stopped_)
145 return;
146 DCHECK(sink_.get());
147 sink_->SetVolume(volume);
150 void AudioRendererImpl::DoPlay() {
151 earliest_end_time_ = base::Time::Now();
152 DCHECK(sink_.get());
153 sink_->Play();
156 void AudioRendererImpl::DoPause() {
157 DCHECK(sink_.get());
158 sink_->Pause(false);
161 void AudioRendererImpl::DoSeek() {
162 earliest_end_time_ = base::Time::Now();
164 // Pause and flush the stream when we seek to a new location.
165 DCHECK(sink_.get());
166 sink_->Pause(true);
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;
179 // Adjust the playback delay.
180 base::TimeDelta request_delay =
181 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
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())));
190 int bytes_per_frame = audio_parameters_.GetBytesPerFrame();
192 const size_t buf_size = number_of_frames * bytes_per_frame;
193 scoped_array<uint8> buf(new uint8[buf_size]);
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());
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);
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,
215 sizeof(float) * frames_to_zero);
218 return frames_filled;
221 void AudioRendererImpl::OnRenderError() {
222 host()->DisableAudioRenderer();
225 void AudioRendererImpl::OnRenderEndOfStream() {
226 // TODO(enal): schedule callback instead of polling.
227 if (base::Time::Now() >= earliest_end_time_)
228 SignalEndOfStream();