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

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

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

Powered by Google App Engine
This is Rietveld 408576698