Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Side by Side Diff: content/renderer/media/audio_renderer_impl.cc

Issue 8785008: Simplify AudioRendererImpl by using AudioDevice. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update stale comment Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/audio_renderer_impl.h" 5 #include "content/renderer/media/audio_renderer_impl.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "content/common/child_process.h" 12 #include "content/common/child_process.h"
14 #include "content/common/media/audio_messages.h" 13 #include "content/common/media/audio_messages.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/renderer/render_thread_impl.h" 14 #include "content/renderer/render_thread_impl.h"
17 #include "media/audio/audio_buffers_state.h" 15 #include "media/audio/audio_buffers_state.h"
18 #include "media/audio/audio_output_controller.h"
19 #include "media/audio/audio_util.h" 16 #include "media/audio/audio_util.h"
20 #include "media/base/filter_host.h"
21 17
22 // Static variable that says what code path we are using -- low or high 18 // We define GetBufferSizeForSampleRate() instead of using
23 // latency. Made separate variable so we don't have to go to command line 19 // GetAudioHardwareBufferSize() in audio_util because we're using
24 // for every DCHECK(). 20 // the AUDIO_PCM_LINEAR flag, instead of AUDIO_PCM_LOW_LATENCY,
25 AudioRendererImpl::LatencyType AudioRendererImpl::latency_type_ = 21 // which the audio_util functions assume.
26 AudioRendererImpl::kUninitializedLatency; 22 //
23 // See: http://code.google.com/p/chromium/issues/detail?id=103627
24 // for a more detailed description of the subtleties.
25 static size_t GetBufferSizeForSampleRate(int sample_rate) {
26 // kNominalBufferSize has been tested on Windows, Mac OS X, and Linux
27 // using the low-latency audio codepath (SyncSocket implementation)
28 // with the AUDIO_PCM_LINEAR flag.
29 const size_t kNominalBufferSize = 2048;
30
31 if (sample_rate <= 48000)
32 return kNominalBufferSize;
33 else if (sample_rate <= 96000)
34 return kNominalBufferSize * 2;
35 return kNominalBufferSize * 4;
36 }
27 37
28 AudioRendererImpl::AudioRendererImpl() 38 AudioRendererImpl::AudioRendererImpl()
29 : AudioRendererBase(), 39 : AudioRendererBase(),
30 bytes_per_second_(0), 40 bytes_per_second_(0),
31 stream_created_(false), 41 stopped_(false) {
32 stream_id_(0), 42 // We create the AudioDevice here because it must be created in the
33 shared_memory_(NULL), 43 // main thread. But we don't yet know the audio format (sample-rate, etc.)
34 shared_memory_size_(0), 44 // at this point. Later, when OnInitialize() is called, we have
35 stopped_(false), 45 // the audio format information and call the AudioDevice::Initialize()
36 pending_request_(false) { 46 // method to fully initialize it.
37 filter_ = RenderThreadImpl::current()->audio_message_filter(); 47 audio_device_ = new AudioDevice();
38 // Figure out if we are planning to use high or low latency code path.
39 // We are initializing only one variable and double initialization is Ok,
40 // so there would not be any issues caused by CPU memory model.
41 if (latency_type_ == kUninitializedLatency) {
42 // Urgent workaround for
43 // http://code.google.com/p/chromium-os/issues/detail?id=21491
44 // TODO(enal): Fix it properly.
45 #if defined(OS_CHROMEOS)
46 latency_type_ = kHighLatency;
47 #else
48 if (!CommandLine::ForCurrentProcess()->HasSwitch(
49 switches::kHighLatencyAudio)) {
50 latency_type_ = kLowLatency;
51 } else {
52 latency_type_ = kHighLatency;
53 }
54 #endif
55 }
56 } 48 }
57 49
58 AudioRendererImpl::~AudioRendererImpl() { 50 AudioRendererImpl::~AudioRendererImpl() {
59 } 51 }
60 52
61 // static
62 void AudioRendererImpl::set_latency_type(LatencyType latency_type) {
63 DCHECK_EQ(kUninitializedLatency, latency_type_);
64 latency_type_ = latency_type;
65 }
66
67 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { 53 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) {
68 if (bytes_per_second_) { 54 if (bytes_per_second_) {
69 return base::TimeDelta::FromMicroseconds( 55 return base::TimeDelta::FromMicroseconds(
70 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); 56 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_);
71 } 57 }
72 return base::TimeDelta(); 58 return base::TimeDelta();
73 } 59 }
74 60
75 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled, 61 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled,
76 base::TimeDelta request_delay, 62 base::TimeDelta request_delay,
77 base::Time time_now) { 63 base::Time time_now) {
78 if (bytes_filled != 0) { 64 if (bytes_filled != 0) {
79 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled); 65 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled);
80 float playback_rate = GetPlaybackRate(); 66 float playback_rate = GetPlaybackRate();
81 if (playback_rate != 1.0f) { 67 if (playback_rate != 1.0f) {
82 predicted_play_time = base::TimeDelta::FromMicroseconds( 68 predicted_play_time = base::TimeDelta::FromMicroseconds(
83 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * 69 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() *
84 playback_rate))); 70 playback_rate)));
85 } 71 }
86 earliest_end_time_ = 72 earliest_end_time_ =
87 std::max(earliest_end_time_, 73 std::max(earliest_end_time_,
88 time_now + request_delay + predicted_play_time); 74 time_now + request_delay + predicted_play_time);
89 } 75 }
90 } 76 }
91 77
92 bool AudioRendererImpl::OnInitialize(int bits_per_channel, 78 bool AudioRendererImpl::OnInitialize(int bits_per_channel,
93 ChannelLayout channel_layout, 79 ChannelLayout channel_layout,
94 int sample_rate) { 80 int sample_rate) {
95 AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, channel_layout, 81 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY
96 sample_rate, bits_per_channel, 0); 82 // does not currently support all the sample-rates that we require.
83 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627
84 // for more details.
85 audio_parameters_ = AudioParameters(AudioParameters::AUDIO_PCM_LINEAR,
86 channel_layout,
87 sample_rate,
88 bits_per_channel,
89 0);
97 90
98 bytes_per_second_ = params.GetBytesPerSecond(); 91 bytes_per_second_ = audio_parameters_.GetBytesPerSecond();
99 92
100 ChildProcess::current()->io_message_loop()->PostTask( 93 DCHECK(audio_device_.get());
101 FROM_HERE, 94
102 base::Bind(&AudioRendererImpl::CreateStreamTask, this, params)); 95 if (!audio_device_->IsInitialized()) {
96 audio_device_->Initialize(
97 GetBufferSizeForSampleRate(sample_rate),
98 audio_parameters_.channels,
99 audio_parameters_.sample_rate,
100 audio_parameters_.format,
101 this);
102
103 audio_device_->Start();
104 }
105
103 return true; 106 return true;
104 } 107 }
105 108
106 void AudioRendererImpl::OnStop() { 109 void AudioRendererImpl::OnStop() {
107 // Since joining with the audio thread can acquire lock_, we make sure to
108 // Join() with it not under lock.
109 base::DelegateSimpleThread* audio_thread = NULL;
110 {
111 base::AutoLock auto_lock(lock_);
112 if (stopped_)
113 return;
114 stopped_ = true;
115
116 DCHECK_EQ(!audio_thread_.get(), !socket_.get());
117 if (socket_.get())
118 socket_->Close();
119 if (audio_thread_.get())
120 audio_thread = audio_thread_.get();
121
122 ChildProcess::current()->io_message_loop()->PostTask(
123 FROM_HERE,
124 base::Bind(&AudioRendererImpl::DestroyTask, this));
125 }
126
127 if (audio_thread)
128 audio_thread->Join();
129 }
130
131 void AudioRendererImpl::NotifyDataAvailableIfNecessary() {
132 if (latency_type_ == kHighLatency) {
133 // Post a task to render thread to notify a packet reception.
134 ChildProcess::current()->io_message_loop()->PostTask(
135 FROM_HERE,
136 base::Bind(&AudioRendererImpl::NotifyPacketReadyTask, this));
137 }
138 }
139
140 void AudioRendererImpl::ConsumeAudioSamples(
141 scoped_refptr<media::Buffer> buffer_in) {
142 base::AutoLock auto_lock(lock_);
143 if (stopped_) 110 if (stopped_)
144 return; 111 return;
145 112
146 // TODO(hclam): handle end of stream here. 113 DCHECK(audio_device_.get());
114 audio_device_->Stop();
147 115
148 // Use the base class to queue the buffer. 116 stopped_ = true;
149 AudioRendererBase::ConsumeAudioSamples(buffer_in);
150
151 NotifyDataAvailableIfNecessary();
152 } 117 }
153 118
154 void AudioRendererImpl::SetPlaybackRate(float rate) { 119 void AudioRendererImpl::SetPlaybackRate(float rate) {
155 DCHECK_LE(0.0f, rate); 120 DCHECK_LE(0.0f, rate);
156 121
157 base::AutoLock auto_lock(lock_);
158 // Handle the case where we stopped due to IO message loop dying. 122 // Handle the case where we stopped due to IO message loop dying.
159 if (stopped_) { 123 if (stopped_) {
160 AudioRendererBase::SetPlaybackRate(rate); 124 AudioRendererBase::SetPlaybackRate(rate);
161 return; 125 return;
162 } 126 }
163 127
164 // We have two cases here: 128 // We have two cases here:
165 // Play: GetPlaybackRate() == 0.0 && rate != 0.0 129 // Play: GetPlaybackRate() == 0.0 && rate != 0.0
166 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0 130 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0
167 if (GetPlaybackRate() == 0.0f && rate != 0.0f) { 131 if (GetPlaybackRate() == 0.0f && rate != 0.0f) {
168 ChildProcess::current()->io_message_loop()->PostTask( 132 DoPlay();
169 FROM_HERE,
170 base::Bind(&AudioRendererImpl::PlayTask, this));
171 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) { 133 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) {
172 // Pause is easy, we can always pause. 134 // Pause is easy, we can always pause.
173 ChildProcess::current()->io_message_loop()->PostTask( 135 DoPause();
174 FROM_HERE,
175 base::Bind(&AudioRendererImpl::PauseTask, this));
176 } 136 }
177 AudioRendererBase::SetPlaybackRate(rate); 137 AudioRendererBase::SetPlaybackRate(rate);
178
179 // If we are playing, give a kick to try fulfilling the packet request as
180 // the previous packet request may be stalled by a pause.
181 if (rate > 0.0f) {
182 NotifyDataAvailableIfNecessary();
183 }
184 } 138 }
185 139
186 void AudioRendererImpl::Pause(const base::Closure& callback) { 140 void AudioRendererImpl::Pause(const base::Closure& callback) {
187 AudioRendererBase::Pause(callback); 141 AudioRendererBase::Pause(callback);
188 base::AutoLock auto_lock(lock_);
189 if (stopped_) 142 if (stopped_)
190 return; 143 return;
191 144
192 ChildProcess::current()->io_message_loop()->PostTask( 145 DoPause();
193 FROM_HERE,
194 base::Bind(&AudioRendererImpl::PauseTask, this));
195 } 146 }
196 147
197 void AudioRendererImpl::Seek(base::TimeDelta time, 148 void AudioRendererImpl::Seek(base::TimeDelta time,
198 const media::FilterStatusCB& cb) { 149 const media::FilterStatusCB& cb) {
199 AudioRendererBase::Seek(time, cb); 150 AudioRendererBase::Seek(time, cb);
200 base::AutoLock auto_lock(lock_);
201 if (stopped_) 151 if (stopped_)
202 return; 152 return;
203 153
204 ChildProcess::current()->io_message_loop()->PostTask( 154 DoSeek();
205 FROM_HERE,
206 base::Bind(&AudioRendererImpl::SeekTask, this));
207 } 155 }
208 156
209
210 void AudioRendererImpl::Play(const base::Closure& callback) { 157 void AudioRendererImpl::Play(const base::Closure& callback) {
211 AudioRendererBase::Play(callback); 158 AudioRendererBase::Play(callback);
212 base::AutoLock auto_lock(lock_);
213 if (stopped_) 159 if (stopped_)
214 return; 160 return;
215 161
216 if (GetPlaybackRate() != 0.0f) { 162 if (GetPlaybackRate() != 0.0f) {
217 ChildProcess::current()->io_message_loop()->PostTask( 163 DoPlay();
218 FROM_HERE,
219 base::Bind(&AudioRendererImpl::PlayTask, this));
220 } else { 164 } else {
221 ChildProcess::current()->io_message_loop()->PostTask( 165 DoPause();
222 FROM_HERE,
223 base::Bind(&AudioRendererImpl::PauseTask, this));
224 } 166 }
225 } 167 }
226 168
227 void AudioRendererImpl::SetVolume(float volume) { 169 void AudioRendererImpl::SetVolume(float volume) {
228 base::AutoLock auto_lock(lock_);
229 if (stopped_) 170 if (stopped_)
230 return; 171 return;
231 ChildProcess::current()->io_message_loop()->PostTask( 172 DCHECK(audio_device_.get());
232 FROM_HERE, 173 audio_device_->SetVolume(volume);
233 base::Bind(&AudioRendererImpl::SetVolumeTask, this, volume));
234 } 174 }
235 175
236 void AudioRendererImpl::OnCreated(base::SharedMemoryHandle handle, 176 void AudioRendererImpl::DoPlay() {
237 uint32 length) { 177 earliest_end_time_ = base::Time::Now();
238 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 178 DCHECK(audio_device_.get());
239 DCHECK_EQ(kHighLatency, latency_type_); 179 audio_device_->Play();
240
241 base::AutoLock auto_lock(lock_);
242 if (stopped_)
243 return;
244
245 shared_memory_.reset(new base::SharedMemory(handle, false));
246 shared_memory_->Map(length);
247 shared_memory_size_ = length;
248 } 180 }
249 181
250 void AudioRendererImpl::CreateSocket(base::SyncSocket::Handle socket_handle) { 182 void AudioRendererImpl::DoPause() {
251 DCHECK_EQ(kLowLatency, latency_type_); 183 DCHECK(audio_device_.get());
252 #if defined(OS_WIN) 184 audio_device_->Pause(false);
253 DCHECK(socket_handle);
254 #else
255 DCHECK_GE(socket_handle, 0);
256 #endif
257 socket_.reset(new base::SyncSocket(socket_handle));
258 } 185 }
259 186
260 void AudioRendererImpl::CreateAudioThread() { 187 void AudioRendererImpl::DoSeek() {
261 DCHECK_EQ(kLowLatency, latency_type_); 188 earliest_end_time_ = base::Time::Now();
262 audio_thread_.reset( 189
263 new base::DelegateSimpleThread(this, "renderer_audio_thread")); 190 // Pause and flush the stream when we seek to a new location.
264 audio_thread_->Start(); 191 DCHECK(audio_device_.get());
192 audio_device_->Pause(true);
265 } 193 }
266 194
267 void AudioRendererImpl::OnLowLatencyCreated( 195 void AudioRendererImpl::Render(const std::vector<float*>& audio_data,
268 base::SharedMemoryHandle handle, 196 size_t number_of_frames,
269 base::SyncSocket::Handle socket_handle, 197 size_t audio_delay_milliseconds) {
270 uint32 length) { 198 if (stopped_ || GetPlaybackRate() == 0.0f) {
271 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 199 // Output silence if stopped.
272 DCHECK_EQ(kLowLatency, latency_type_); 200 for (size_t i = 0; i < audio_data.size(); ++i)
273 #if defined(OS_WIN) 201 memset(audio_data[i], 0, sizeof(float) * number_of_frames);
274 DCHECK(handle);
275 #else
276 DCHECK_GE(handle.fd, 0);
277 #endif
278 DCHECK_NE(0u, length);
279
280 base::AutoLock auto_lock(lock_);
281 if (stopped_)
282 return; 202 return;
283
284 shared_memory_.reset(new base::SharedMemory(handle, false));
285 shared_memory_->Map(media::TotalSharedMemorySizeInBytes(length));
286 shared_memory_size_ = length;
287
288 CreateSocket(socket_handle);
289 CreateAudioThread();
290 }
291
292 void AudioRendererImpl::OnRequestPacket(AudioBuffersState buffers_state) {
293 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
294 DCHECK_EQ(kHighLatency, latency_type_);
295 {
296 base::AutoLock auto_lock(lock_);
297 DCHECK(!pending_request_);
298 pending_request_ = true;
299 request_buffers_state_ = buffers_state;
300 } 203 }
301 204
302 // Try to fill in the fulfill the packet request. 205 // Adjust the playback delay.
303 NotifyPacketReadyTask(); 206 base::Time current_time = base::Time::Now();
304 }
305 207
306 void AudioRendererImpl::OnStateChanged(AudioStreamState state) { 208 base::TimeDelta request_delay =
307 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 209 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
308 210
309 base::AutoLock auto_lock(lock_); 211 // Finally we need to adjust the delay according to playback rate.
310 if (stopped_) 212 if (GetPlaybackRate() != 1.0f) {
311 return; 213 request_delay = base::TimeDelta::FromMicroseconds(
214 static_cast<int64>(ceil(request_delay.InMicroseconds() *
215 GetPlaybackRate())));
216 }
312 217
313 switch (state) { 218 uint32 bytes_per_frame =
314 case kAudioStreamError: 219 audio_parameters_.bits_per_sample * audio_parameters_.channels / 8;
315 // We receive this error if we counter an hardware error on the browser 220
316 // side. We can proceed with ignoring the audio stream. 221 const size_t buf_size = number_of_frames * bytes_per_frame;
317 // TODO(hclam): We need more handling of these kind of error. For example 222 scoped_array<uint8> buf(new uint8[buf_size]);
318 // re-try creating the audio output stream on the browser side or fail 223
319 // nicely and report to demuxer that the whole audio stream is discarded. 224 base::Time time_now = base::Time::Now();
320 host()->DisableAudioRenderer(); 225 uint32 filled = FillBuffer(buf.get(),
321 break; 226 buf_size,
322 // TODO(hclam): handle these events. 227 request_delay,
323 case kAudioStreamPlaying: 228 time_now >= earliest_end_time_);
324 case kAudioStreamPaused: 229 DCHECK_LE(filled, buf_size);
325 break; 230
326 default: 231 uint32 filled_frames = filled / bytes_per_frame;
327 NOTREACHED(); 232
328 break; 233 // Deinterleave each audio channel.
234 int channels = audio_data.size();
235 for (int channel_index = 0; channel_index < channels; ++channel_index) {
236 media::DeinterleaveAudioChannel(buf.get(),
237 audio_data[channel_index],
238 channels,
239 channel_index,
240 bytes_per_frame / channels,
241 filled_frames);
242
243 // If FillBuffer() didn't give us enough data then zero out the remainder.
244 if (filled_frames < number_of_frames) {
245 int frames_to_zero = number_of_frames - filled_frames;
246 memset(audio_data[channel_index], 0, sizeof(float) * frames_to_zero);
247 }
329 } 248 }
330 } 249 }
331
332 void AudioRendererImpl::OnVolume(double volume) {
333 // TODO(hclam): decide whether we need to report the current volume to
334 // pipeline.
335 }
336
337 void AudioRendererImpl::CreateStreamTask(const AudioParameters& audio_params) {
338 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
339
340 base::AutoLock auto_lock(lock_);
341 if (stopped_)
342 return;
343
344 stream_created_ = true;
345
346 // Make sure we don't call create more than once.
347 DCHECK_EQ(0, stream_id_);
348 stream_id_ = filter_->AddDelegate(this);
349 ChildProcess::current()->io_message_loop()->AddDestructionObserver(this);
350
351 AudioParameters params_to_send(audio_params);
352 // Let the browser choose packet size.
353 params_to_send.samples_per_packet = 0;
354
355 Send(new AudioHostMsg_CreateStream(stream_id_,
356 params_to_send,
357 latency_type_ == kLowLatency));
358 }
359
360 void AudioRendererImpl::PlayTask() {
361 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
362
363 earliest_end_time_ = base::Time::Now();
364 Send(new AudioHostMsg_PlayStream(stream_id_));
365 }
366
367 void AudioRendererImpl::PauseTask() {
368 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
369
370 Send(new AudioHostMsg_PauseStream(stream_id_));
371 }
372
373 void AudioRendererImpl::SeekTask() {
374 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
375
376 earliest_end_time_ = base::Time::Now();
377 // We have to pause the audio stream before we can flush.
378 Send(new AudioHostMsg_PauseStream(stream_id_));
379 Send(new AudioHostMsg_FlushStream(stream_id_));
380 }
381
382 void AudioRendererImpl::DestroyTask() {
383 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
384
385 base::AutoLock auto_lock(lock_);
386 // Errors can cause us to get here before CreateStreamTask ever ran, in which
387 // case there's nothing to do.
388 if (!stream_created_)
389 return;
390
391 // Make sure we don't call destroy more than once.
392 DCHECK_NE(0, stream_id_);
393 filter_->RemoveDelegate(stream_id_);
394 Send(new AudioHostMsg_CloseStream(stream_id_));
395 // During shutdown this may be NULL; don't worry about deregistering in that
396 // case.
397 if (ChildProcess::current())
398 ChildProcess::current()->io_message_loop()->RemoveDestructionObserver(this);
399 stream_id_ = 0;
400 }
401
402 void AudioRendererImpl::SetVolumeTask(double volume) {
403 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
404
405 base::AutoLock auto_lock(lock_);
406 if (stopped_)
407 return;
408 Send(new AudioHostMsg_SetVolume(stream_id_, volume));
409 }
410
411 void AudioRendererImpl::NotifyPacketReadyTask() {
412 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
413 DCHECK_EQ(kHighLatency, latency_type_);
414
415 base::AutoLock auto_lock(lock_);
416 if (stopped_)
417 return;
418 if (pending_request_ && GetPlaybackRate() > 0.0f) {
419 DCHECK(shared_memory_.get());
420
421 // Adjust the playback delay.
422 base::Time current_time = base::Time::Now();
423
424 base::TimeDelta request_delay =
425 ConvertToDuration(request_buffers_state_.total_bytes());
426
427 // Add message delivery delay.
428 if (current_time > request_buffers_state_.timestamp) {
429 base::TimeDelta receive_latency =
430 current_time - request_buffers_state_.timestamp;
431
432 // If the receive latency is too much it may offset all the delay.
433 if (receive_latency >= request_delay) {
434 request_delay = base::TimeDelta();
435 } else {
436 request_delay -= receive_latency;
437 }
438 }
439
440 // Finally we need to adjust the delay according to playback rate.
441 if (GetPlaybackRate() != 1.0f) {
442 request_delay = base::TimeDelta::FromMicroseconds(
443 static_cast<int64>(ceil(request_delay.InMicroseconds() *
444 GetPlaybackRate())));
445 }
446
447 bool buffer_empty = (request_buffers_state_.pending_bytes == 0) &&
448 (current_time >= earliest_end_time_);
449
450 // For high latency mode we don't write length into shared memory,
451 // it is explicit part of AudioHostMsg_NotifyPacketReady() message,
452 // so no need to reserve first word of buffer for length.
453 uint32 filled = FillBuffer(static_cast<uint8*>(shared_memory_->memory()),
454 shared_memory_size_, request_delay,
455 buffer_empty);
456 UpdateEarliestEndTime(filled, request_delay, current_time);
457 pending_request_ = false;
458
459 // Then tell browser process we are done filling into the buffer.
460 Send(new AudioHostMsg_NotifyPacketReady(stream_id_, filled));
461 }
462 }
463
464 void AudioRendererImpl::WillDestroyCurrentMessageLoop() {
465 DCHECK(!ChildProcess::current() || // During shutdown.
466 (MessageLoop::current() ==
467 ChildProcess::current()->io_message_loop()));
468
469 // We treat the IO loop going away the same as stopping.
470 {
471 base::AutoLock auto_lock(lock_);
472 if (stopped_)
473 return;
474
475 stopped_ = true;
476 }
477 DestroyTask();
478 }
479
480 // Our audio thread runs here. We receive requests for more data and send it
481 // on this thread.
482 void AudioRendererImpl::Run() {
483 DCHECK_EQ(kLowLatency, latency_type_);
484 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
485
486 int bytes;
487 while (sizeof(bytes) == socket_->Receive(&bytes, sizeof(bytes))) {
488 if (bytes == media::AudioOutputController::kPauseMark) {
489 // When restarting playback, host should get new data,
490 // not what is currently in the buffer.
491 media::SetActualDataSizeInBytes(shared_memory_.get(),
492 shared_memory_size_,
493 0);
494 continue;
495 }
496 else if (bytes < 0)
497 break;
498 base::AutoLock auto_lock(lock_);
499 if (stopped_)
500 break;
501 float playback_rate = GetPlaybackRate();
502 if (playback_rate <= 0.0f)
503 continue;
504 DCHECK(shared_memory_.get());
505 base::TimeDelta request_delay = ConvertToDuration(bytes);
506
507 // We need to adjust the delay according to playback rate.
508 if (playback_rate != 1.0f) {
509 request_delay = base::TimeDelta::FromMicroseconds(
510 static_cast<int64>(ceil(request_delay.InMicroseconds() *
511 playback_rate)));
512 }
513 base::Time time_now = base::Time::Now();
514 uint32 size = FillBuffer(static_cast<uint8*>(shared_memory_->memory()),
515 shared_memory_size_,
516 request_delay,
517 time_now >= earliest_end_time_);
518 media::SetActualDataSizeInBytes(shared_memory_.get(),
519 shared_memory_size_,
520 size);
521 UpdateEarliestEndTime(size, request_delay, time_now);
522 }
523 }
524
525 void AudioRendererImpl::Send(IPC::Message* message) {
526 filter_->Send(message);
527 }
OLDNEW
« no previous file with comments | « content/renderer/media/audio_renderer_impl.h ('k') | content/renderer/media/audio_renderer_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698