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 |