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

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

Issue 7631033: Very early implementation for HTMLMediaElement / Web Audio API integration (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 4 months 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 "base/command_line.h"
9 #include "content/common/child_process.h" 10 #include "content/common/child_process.h"
10 #include "base/command_line.h"
11 #include "content/common/content_switches.h" 11 #include "content/common/content_switches.h"
12 #include "content/common/media/audio_messages.h" 12 #include "content/common/media/audio_messages.h"
13 #include "content/renderer/render_thread.h" 13 #include "content/renderer/render_thread.h"
14 #include "content/renderer/render_view.h" 14 #include "content/renderer/render_view.h"
15 #include "media/audio/audio_output_controller.h" 15 #include "media/audio/audio_output_controller.h"
16 #include "media/base/filter_host.h" 16 #include "media/base/filter_host.h"
17 17
18 // Static variable that says what code path we are using -- low or high 18 const size_t kBufferSize = 128; //2048;
19 // latency. Made separate variable so we don't have to go to command line
20 // for every DCHECK().
21 AudioRendererImpl::LatencyType AudioRendererImpl::latency_type_ =
22 AudioRendererImpl::kUninitializedLatency;
23 19
24 AudioRendererImpl::AudioRendererImpl() 20 AudioRendererImpl::AudioRendererImpl(MessageLoop* render_loop)
25 : AudioRendererBase(), 21 : AudioRendererBase(),
26 bytes_per_second_(0), 22 bytes_per_second_(0),
27 stream_id_(0),
28 shared_memory_(NULL),
29 shared_memory_size_(0),
30 stopped_(false), 23 stopped_(false),
31 pending_request_(false), 24 pending_request_(false),
32 prerolling_(false), 25 prerolling_(false),
33 preroll_bytes_(0) { 26 preroll_bytes_(0),
34 filter_ = RenderThread::current()->audio_message_filter(); 27 render_loop_(render_loop) {
35 // Figure out if we are planning to use high or low latency code path.
36 // We are initializing only one variable and double initialization is Ok,
37 // so there would not be any issues caused by CPU memory model.
38 if (latency_type_ == kUninitializedLatency) {
39 if (CommandLine::ForCurrentProcess()->HasSwitch(
40 switches::kLowLatencyAudio)) {
41 latency_type_ = kLowLatency;
42 } else {
43 latency_type_ = kHighLatency;
44 }
45 }
46 } 28 }
47 29
48 AudioRendererImpl::~AudioRendererImpl() { 30 AudioRendererImpl::~AudioRendererImpl() {
49 } 31 }
50 32
51 // static
52 void AudioRendererImpl::set_latency_type(LatencyType latency_type) {
53 DCHECK_EQ(kUninitializedLatency, latency_type_);
54 latency_type_ = latency_type;
55 }
56
57 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { 33 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) {
58 if (bytes_per_second_) { 34 if (bytes_per_second_) {
59 return base::TimeDelta::FromMicroseconds( 35 return base::TimeDelta::FromMicroseconds(
60 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); 36 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_);
61 } 37 }
62 return base::TimeDelta(); 38 return base::TimeDelta();
63 } 39 }
64 40
65 bool AudioRendererImpl::OnInitialize(const media::AudioDecoderConfig& config) { 41 bool AudioRendererImpl::OnInitialize(const media::AudioDecoderConfig& config) {
66 AudioParameters params(config); 42 AudioParameters params(config);
67 params.format = AudioParameters::AUDIO_PCM_LINEAR; 43 render_loop_->PostTask(
68
69 bytes_per_second_ = params.GetBytesPerSecond();
70
71 ChildProcess::current()->io_message_loop()->PostTask(
72 FROM_HERE, 44 FROM_HERE,
73 NewRunnableMethod(this, &AudioRendererImpl::CreateStreamTask, params)); 45 NewRunnableMethod(this, &AudioRendererImpl::InitializeTask, params));
74 return true; 46 return true;
75 } 47 }
76 48
77 void AudioRendererImpl::OnStop() { 49 void AudioRendererImpl::OnStop() {
78 base::AutoLock auto_lock(lock_); 50 base::AutoLock auto_lock(lock_);
79 if (stopped_) 51 if (stopped_)
80 return; 52 return;
81 stopped_ = true; 53 stopped_ = true;
82 54
83 ChildProcess::current()->io_message_loop()->PostTask( 55 if (audio_device_.get()) {
84 FROM_HERE, 56 audio_device_->Stop();
85 NewRunnableMethod(this, &AudioRendererImpl::DestroyTask)); 57 audio_device_ = NULL;
86
87 if (audio_thread_.get()) {
88 socket_->Close();
89 audio_thread_->Join();
90 }
91 }
92
93 void AudioRendererImpl::NotifyDataAvailableIfNecessary() {
94 if (latency_type_ == kHighLatency) {
95 // Post a task to render thread to notify a packet reception.
96 ChildProcess::current()->io_message_loop()->PostTask(
97 FROM_HERE,
98 NewRunnableMethod(this, &AudioRendererImpl::NotifyPacketReadyTask));
99 } 58 }
100 } 59 }
101 60
102 void AudioRendererImpl::ConsumeAudioSamples( 61 void AudioRendererImpl::ConsumeAudioSamples(
103 scoped_refptr<media::Buffer> buffer_in) { 62 scoped_refptr<media::Buffer> buffer_in) {
104 base::AutoLock auto_lock(lock_); 63 base::AutoLock auto_lock(lock_);
105 if (stopped_) 64 if (stopped_)
106 return; 65 return;
107 66
108 // TODO(hclam): handle end of stream here. 67 // TODO(hclam): handle end of stream here.
109 68
110 // Use the base class to queue the buffer. 69 // Use the base class to queue the buffer.
111 AudioRendererBase::ConsumeAudioSamples(buffer_in); 70 AudioRendererBase::ConsumeAudioSamples(buffer_in);
112 71
113 NotifyDataAvailableIfNecessary(); 72 }
73
74 void AudioRendererImpl::Render(const std::vector<float*>& audio_data,
scherkus (not reviewing) 2011/08/23 15:16:01 I haven't taken an indepth look at this class but
Chris Rogers 2011/08/24 00:41:52 Agreed. Also, we should loop Aaron into the conve
75 size_t number_of_frames,
76 size_t audio_delay_milliseconds) {
77 // LOG(ERROR) << "Render("<< audio_data.size() << ", "
78 // << number_of_frames << ", "
79 // << audio_delay_milliseconds << ")";
80
81 base::AutoLock auto_lock(lock_);
82 if (stopped_)
83 return;
84
85 if (GetPlaybackRate() > 0.0f) {
86 // Adjust the playback delay.
87 base::Time current_time = base::Time::Now();
88
89 base::TimeDelta request_delay =
90 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
91
92 // Finally we need to adjust the delay according to playback rate.
93 if (GetPlaybackRate() != 1.0f) {
94 request_delay = base::TimeDelta::FromMicroseconds(
95 static_cast<int64>(ceil(request_delay.InMicroseconds() *
96 GetPlaybackRate())));
97 }
98
99 int buf_size = number_of_frames * bytes_per_frame_;
100 int bytes_per_sample = bytes_per_frame_ / audio_data.size();
101 DCHECK_EQ(bytes_per_sample, 2);
102 scoped_array<uint8> buf(new uint8[buf_size]);
103 uint32 filled = FillBuffer(buf.get(), buf_size, request_delay, false);
104 uint32 filled_frames = filled / bytes_per_frame_;
105 int stride = audio_data.size();
106 for (size_t i = 0; i < audio_data.size(); ++i) {
107 short* pSrc = reinterpret_cast<short*>(buf.get()) + i;
108 float* pDst = audio_data[i];
109
110 for (size_t j = 0; j < filled_frames; ++j) {
111 *pDst++ = *pSrc / 32768.0f;
112 pSrc += stride;
113 }
114 }
115 }
116 }
117
118 void AudioRendererImpl::SetAudioSink(AudioSink* audio_sink)
119 {
120 if (audio_device_.get()) {
121 audio_device_->Stop();
122 }
123
124 audio_device_ = audio_sink;
114 } 125 }
115 126
116 void AudioRendererImpl::SetPlaybackRate(float rate) { 127 void AudioRendererImpl::SetPlaybackRate(float rate) {
117 DCHECK_LE(0.0f, rate); 128 DCHECK_LE(0.0f, rate);
118 129
119 base::AutoLock auto_lock(lock_); 130 base::AutoLock auto_lock(lock_);
120 // Handle the case where we stopped due to IO message loop dying. 131 // Handle the case where we stopped due to IO message loop dying.
121 if (stopped_) { 132 if (stopped_) {
122 AudioRendererBase::SetPlaybackRate(rate); 133 AudioRendererBase::SetPlaybackRate(rate);
123 return; 134 return;
124 } 135 }
125 136
126 // We have two cases here: 137 // We have two cases here:
127 // Play: GetPlaybackRate() == 0.0 && rate != 0.0 138 // Play: GetPlaybackRate() == 0.0 && rate != 0.0
128 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0 139 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0
129 if (GetPlaybackRate() == 0.0f && rate != 0.0f) { 140 if (GetPlaybackRate() == 0.0f && rate != 0.0f) {
130 ChildProcess::current()->io_message_loop()->PostTask( 141 render_loop_->PostTask(
131 FROM_HERE, 142 FROM_HERE,
132 NewRunnableMethod(this, &AudioRendererImpl::PlayTask)); 143 NewRunnableMethod(this, &AudioRendererImpl::PlayTask));
133 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) { 144 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) {
134 // Pause is easy, we can always pause. 145 // Pause is easy, we can always pause.
135 ChildProcess::current()->io_message_loop()->PostTask( 146 render_loop_->PostTask(
136 FROM_HERE, 147 FROM_HERE,
137 NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); 148 NewRunnableMethod(this, &AudioRendererImpl::PauseTask));
138 } 149 }
139 AudioRendererBase::SetPlaybackRate(rate); 150 AudioRendererBase::SetPlaybackRate(rate);
140
141 // If we are playing, give a kick to try fulfilling the packet request as
142 // the previous packet request may be stalled by a pause.
143 if (rate > 0.0f) {
144 NotifyDataAvailableIfNecessary();
145 }
146 } 151 }
147 152
148 void AudioRendererImpl::Pause(media::FilterCallback* callback) { 153 void AudioRendererImpl::Pause(media::FilterCallback* callback) {
149 AudioRendererBase::Pause(callback); 154 AudioRendererBase::Pause(callback);
150 base::AutoLock auto_lock(lock_); 155 base::AutoLock auto_lock(lock_);
151 if (stopped_) 156 if (stopped_)
152 return; 157 return;
153 158
154 ChildProcess::current()->io_message_loop()->PostTask( 159 render_loop_->PostTask(
155 FROM_HERE, 160 FROM_HERE,
156 NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); 161 NewRunnableMethod(this, &AudioRendererImpl::PauseTask));
157 } 162 }
158 163
159 void AudioRendererImpl::Seek(base::TimeDelta time, 164 void AudioRendererImpl::Seek(base::TimeDelta time,
160 const media::FilterStatusCB& cb) { 165 const media::FilterStatusCB& cb) {
161 AudioRendererBase::Seek(time, cb); 166 AudioRendererBase::Seek(time, cb);
162 base::AutoLock auto_lock(lock_); 167 base::AutoLock auto_lock(lock_);
163 if (stopped_) 168 if (stopped_)
164 return; 169 return;
165 170
166 ChildProcess::current()->io_message_loop()->PostTask( 171 render_loop_->PostTask(
167 FROM_HERE, 172 FROM_HERE,
168 NewRunnableMethod(this, &AudioRendererImpl::SeekTask)); 173 NewRunnableMethod(this, &AudioRendererImpl::SeekTask));
169 } 174 }
170 175
171 176
172 void AudioRendererImpl::Play(media::FilterCallback* callback) { 177 void AudioRendererImpl::Play(media::FilterCallback* callback) {
173 AudioRendererBase::Play(callback); 178 AudioRendererBase::Play(callback);
174 base::AutoLock auto_lock(lock_); 179 base::AutoLock auto_lock(lock_);
175 if (stopped_) 180 if (stopped_)
176 return; 181 return;
177 182
178 if (GetPlaybackRate() != 0.0f) { 183 if (GetPlaybackRate() != 0.0f) {
179 ChildProcess::current()->io_message_loop()->PostTask( 184 render_loop_->PostTask(
180 FROM_HERE, 185 FROM_HERE,
181 NewRunnableMethod(this, &AudioRendererImpl::PlayTask)); 186 NewRunnableMethod(this, &AudioRendererImpl::PlayTask));
182 } else { 187 } else {
183 ChildProcess::current()->io_message_loop()->PostTask( 188 render_loop_->PostTask(
184 FROM_HERE, 189 FROM_HERE,
185 NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); 190 NewRunnableMethod(this, &AudioRendererImpl::PauseTask));
186 } 191 }
187 } 192 }
188 193
189 void AudioRendererImpl::SetVolume(float volume) { 194 void AudioRendererImpl::SetVolume(float volume) {
190 base::AutoLock auto_lock(lock_); 195 base::AutoLock auto_lock(lock_);
191 if (stopped_) 196 if (stopped_)
192 return; 197 return;
193 ChildProcess::current()->io_message_loop()->PostTask(
194 FROM_HERE,
195 NewRunnableMethod(this, &AudioRendererImpl::SetVolumeTask, volume));
196 }
197
198 void AudioRendererImpl::OnCreated(base::SharedMemoryHandle handle,
199 uint32 length) {
200 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
201 DCHECK_EQ(kHighLatency, latency_type_);
202
203 base::AutoLock auto_lock(lock_);
204 if (stopped_)
205 return;
206 198
207 shared_memory_.reset(new base::SharedMemory(handle, false)); 199 if (audio_device_.get())
208 shared_memory_->Map(length); 200 audio_device_->SetVolume(volume);
209 shared_memory_size_ = length;
210 } 201 }
211 202
212 void AudioRendererImpl::CreateSocket(base::SyncSocket::Handle socket_handle) { 203 void AudioRendererImpl::InitializeTask(const AudioParameters& params) {
213 DCHECK_EQ(kLowLatency, latency_type_); 204 bytes_per_second_ = params.GetBytesPerSecond();
214 #if defined(OS_WIN) 205 bytes_per_frame_ = params.bits_per_sample * params.channels / 8;
215 DCHECK(socket_handle); 206
216 #else 207 audio_device_ = new AudioDevice(
217 DCHECK_GE(socket_handle, 0); 208 kBufferSize,
218 #endif 209 params.channels,
219 socket_.reset(new base::SyncSocket(socket_handle)); 210 params.sample_rate,
211 this);
220 } 212 }
221 213
222 void AudioRendererImpl::CreateAudioThread() { 214 void AudioRendererImpl::PlayTask() {
223 DCHECK_EQ(kLowLatency, latency_type_); 215 LOG(ERROR) << "PlayTask()";
224 audio_thread_.reset(
225 new base::DelegateSimpleThread(this, "renderer_audio_thread"));
226 audio_thread_->Start();
227 }
228 216
229 void AudioRendererImpl::OnLowLatencyCreated( 217 //Send(new AudioHostMsg_PlayStream(stream_id_));
230 base::SharedMemoryHandle handle, 218 if (audio_device_.get()) {
231 base::SyncSocket::Handle socket_handle, 219 audio_device_->Start();
232 uint32 length) {
233 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
234 DCHECK_EQ(kLowLatency, latency_type_);
235 #if defined(OS_WIN)
236 DCHECK(handle);
237 #else
238 DCHECK_GE(handle.fd, 0);
239 #endif
240 DCHECK_NE(0u, length);
241
242 base::AutoLock auto_lock(lock_);
243 if (stopped_)
244 return;
245
246 shared_memory_.reset(new base::SharedMemory(handle, false));
247 shared_memory_->Map(length);
248 shared_memory_size_ = length;
249
250 CreateSocket(socket_handle);
251 CreateAudioThread();
252 }
253
254 void AudioRendererImpl::OnRequestPacket(AudioBuffersState buffers_state) {
255 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
256 DCHECK_EQ(kHighLatency, latency_type_);
257 {
258 base::AutoLock auto_lock(lock_);
259 DCHECK(!pending_request_);
260 pending_request_ = true;
261 request_buffers_state_ = buffers_state;
262 }
263
264 // Try to fill in the fulfill the packet request.
265 NotifyPacketReadyTask();
266 }
267
268 void AudioRendererImpl::OnStateChanged(AudioStreamState state) {
269 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
270
271 base::AutoLock auto_lock(lock_);
272 if (stopped_)
273 return;
274
275 switch (state) {
276 case kAudioStreamError:
277 // We receive this error if we counter an hardware error on the browser
278 // side. We can proceed with ignoring the audio stream.
279 // TODO(hclam): We need more handling of these kind of error. For example
280 // re-try creating the audio output stream on the browser side or fail
281 // nicely and report to demuxer that the whole audio stream is discarded.
282 host()->DisableAudioRenderer();
283 break;
284 // TODO(hclam): handle these events.
285 case kAudioStreamPlaying:
286 case kAudioStreamPaused:
287 break;
288 default:
289 NOTREACHED();
290 break;
291 } 220 }
292 } 221 }
293 222
294 void AudioRendererImpl::OnVolume(double volume) { 223 void AudioRendererImpl::PauseTask() {
295 // TODO(hclam): decide whether we need to report the current volume to 224 LOG(ERROR) << "PauseTask()";
296 // pipeline.
297 }
298 225
299 void AudioRendererImpl::CreateStreamTask(const AudioParameters& audio_params) { 226 //Send(new AudioHostMsg_PauseStream(stream_id_));
300 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 227 if (audio_device_.get()) {
301 228 audio_device_->Stop();
302 base::AutoLock auto_lock(lock_); 229 }
303 if (stopped_)
304 return;
305
306 // Make sure we don't call create more than once.
307 DCHECK_EQ(0, stream_id_);
308 stream_id_ = filter_->AddDelegate(this);
309 ChildProcess::current()->io_message_loop()->AddDestructionObserver(this);
310
311 AudioParameters params_to_send(audio_params);
312 // Let the browser choose packet size.
313 params_to_send.samples_per_packet = 0;
314
315 Send(new AudioHostMsg_CreateStream(stream_id_,
316 params_to_send,
317 latency_type_ == kLowLatency));
318 }
319
320 void AudioRendererImpl::PlayTask() {
321 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
322
323 Send(new AudioHostMsg_PlayStream(stream_id_));
324 }
325
326 void AudioRendererImpl::PauseTask() {
327 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
328
329 Send(new AudioHostMsg_PauseStream(stream_id_));
330 } 230 }
331 231
332 void AudioRendererImpl::SeekTask() { 232 void AudioRendererImpl::SeekTask() {
333 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 233 LOG(ERROR) << "SeekTask()";
334 234 if (audio_device_.get()) {
235 audio_device_->Stop();
236 }
335 // We have to pause the audio stream before we can flush. 237 // We have to pause the audio stream before we can flush.
336 Send(new AudioHostMsg_PauseStream(stream_id_)); 238 //Send(new AudioHostMsg_PauseStream(stream_id_));
337 Send(new AudioHostMsg_FlushStream(stream_id_)); 239 //Send(new AudioHostMsg_FlushStream(stream_id_));
338 }
339
340 void AudioRendererImpl::DestroyTask() {
341 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
342
343 // Make sure we don't call destroy more than once.
344 DCHECK_NE(0, stream_id_);
345 filter_->RemoveDelegate(stream_id_);
346 Send(new AudioHostMsg_CloseStream(stream_id_));
347 ChildProcess::current()->io_message_loop()->RemoveDestructionObserver(this);
348 stream_id_ = 0;
349 }
350
351 void AudioRendererImpl::SetVolumeTask(double volume) {
352 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
353
354 base::AutoLock auto_lock(lock_);
355 if (stopped_)
356 return;
357 Send(new AudioHostMsg_SetVolume(stream_id_, volume));
358 }
359
360 void AudioRendererImpl::NotifyPacketReadyTask() {
361 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
362 DCHECK_EQ(kHighLatency, latency_type_);
363
364 base::AutoLock auto_lock(lock_);
365 if (stopped_)
366 return;
367 if (pending_request_ && GetPlaybackRate() > 0.0f) {
368 DCHECK(shared_memory_.get());
369
370 // Adjust the playback delay.
371 base::Time current_time = base::Time::Now();
372
373 base::TimeDelta request_delay =
374 ConvertToDuration(request_buffers_state_.total_bytes());
375
376 // Add message delivery delay.
377 if (current_time > request_buffers_state_.timestamp) {
378 base::TimeDelta receive_latency =
379 current_time - request_buffers_state_.timestamp;
380
381 // If the receive latency is too much it may offset all the delay.
382 if (receive_latency >= request_delay) {
383 request_delay = base::TimeDelta();
384 } else {
385 request_delay -= receive_latency;
386 }
387 }
388
389 // Finally we need to adjust the delay according to playback rate.
390 if (GetPlaybackRate() != 1.0f) {
391 request_delay = base::TimeDelta::FromMicroseconds(
392 static_cast<int64>(ceil(request_delay.InMicroseconds() *
393 GetPlaybackRate())));
394 }
395
396 uint32 filled = FillBuffer(static_cast<uint8*>(shared_memory_->memory()),
397 shared_memory_size_, request_delay,
398 request_buffers_state_.pending_bytes == 0);
399 pending_request_ = false;
400 // Then tell browser process we are done filling into the buffer.
401 Send(new AudioHostMsg_NotifyPacketReady(stream_id_, filled));
402 }
403 } 240 }
404 241
405 void AudioRendererImpl::WillDestroyCurrentMessageLoop() { 242 void AudioRendererImpl::WillDestroyCurrentMessageLoop() {
406 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 243 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
407 244
408 // We treat the IO loop going away the same as stopping. 245 // We treat the IO loop going away the same as stopping.
409 base::AutoLock auto_lock(lock_); 246 base::AutoLock auto_lock(lock_);
410 if (stopped_) 247 if (stopped_)
411 return; 248 return;
412 249
413 stopped_ = true; 250 stopped_ = true;
414 DestroyTask(); 251 if (audio_device_.get()) {
415 } 252 audio_device_->Stop();
416 253 audio_device_ = NULL;
417 // Our audio thread runs here. We receive requests for more data and send it
418 // on this thread.
419 void AudioRendererImpl::Run() {
420 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
421
422 int bytes;
423 while (sizeof(bytes) == socket_->Receive(&bytes, sizeof(bytes))) {
424 LOG(ERROR) << "+++ bytes: " << bytes;
425 if (bytes == media::AudioOutputController::kPauseMark)
426 continue;
427 else if (bytes < 0)
428 break;
429 base::AutoLock auto_lock(lock_);
430 if (stopped_)
431 break;
432 float playback_rate = GetPlaybackRate();
433 if (playback_rate <= 0.0f)
434 continue;
435 DCHECK(shared_memory_.get());
436 base::TimeDelta request_delay = ConvertToDuration(bytes);
437 // We need to adjust the delay according to playback rate.
438 if (playback_rate != 1.0f) {
439 request_delay = base::TimeDelta::FromMicroseconds(
440 static_cast<int64>(ceil(request_delay.InMicroseconds() *
441 playback_rate)));
442 }
443 FillBuffer(static_cast<uint8*>(shared_memory_->memory()),
444 shared_memory_size_,
445 request_delay,
446 true /* buffers empty */);
447 } 254 }
448 } 255 }
449
450 void AudioRendererImpl::Send(IPC::Message* message) {
451 filter_->Send(message);
452 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698