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 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 audio_device_(0),
35 // Figure out if we are planning to use high or low latency code path. 28 render_loop_(render_loop) {
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 } 29 }
47 30
48 AudioRendererImpl::~AudioRendererImpl() { 31 AudioRendererImpl::~AudioRendererImpl() {
49 } 32 }
50 33
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) { 34 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) {
58 if (bytes_per_second_) { 35 if (bytes_per_second_) {
59 return base::TimeDelta::FromMicroseconds( 36 return base::TimeDelta::FromMicroseconds(
60 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); 37 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_);
61 } 38 }
62 return base::TimeDelta(); 39 return base::TimeDelta();
63 } 40 }
64 41
65 bool AudioRendererImpl::OnInitialize(const media::AudioDecoderConfig& config) { 42 bool AudioRendererImpl::OnInitialize(const media::AudioDecoderConfig& config) {
66 AudioParameters params(config); 43 AudioParameters params(config);
67 params.format = AudioParameters::AUDIO_PCM_LINEAR; 44 render_loop_->PostTask(
68
69 bytes_per_second_ = params.GetBytesPerSecond();
70
71 ChildProcess::current()->io_message_loop()->PostTask(
72 FROM_HERE, 45 FROM_HERE,
73 NewRunnableMethod(this, &AudioRendererImpl::CreateStreamTask, params)); 46 NewRunnableMethod(this, &AudioRendererImpl::InitializeTask, params));
74 return true; 47 return true;
75 } 48 }
76 49
77 void AudioRendererImpl::OnStop() { 50 void AudioRendererImpl::OnStop() {
78 base::AutoLock auto_lock(lock_); 51 base::AutoLock auto_lock(lock_);
79 if (stopped_) 52 if (stopped_)
80 return; 53 return;
81 stopped_ = true; 54 stopped_ = true;
82 55
83 ChildProcess::current()->io_message_loop()->PostTask( 56 if (audio_device_) {
84 FROM_HERE, 57 audio_device_->Stop();
85 NewRunnableMethod(this, &AudioRendererImpl::DestroyTask)); 58 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 } 59 }
100 } 60 }
101 61
102 void AudioRendererImpl::ConsumeAudioSamples( 62 void AudioRendererImpl::ConsumeAudioSamples(
103 scoped_refptr<media::Buffer> buffer_in) { 63 scoped_refptr<media::Buffer> buffer_in) {
104 base::AutoLock auto_lock(lock_); 64 base::AutoLock auto_lock(lock_);
105 if (stopped_) 65 if (stopped_)
106 return; 66 return;
107 67
108 // TODO(hclam): handle end of stream here. 68 // TODO(hclam): handle end of stream here.
109 69
110 // Use the base class to queue the buffer. 70 // Use the base class to queue the buffer.
111 AudioRendererBase::ConsumeAudioSamples(buffer_in); 71 AudioRendererBase::ConsumeAudioSamples(buffer_in);
112 72
113 NotifyDataAvailableIfNecessary(); 73 }
74
75 void AudioRendererImpl::Render(const std::vector<float*>& audio_data,
76 size_t number_of_frames,
77 size_t audio_delay_milliseconds) {
78 // LOG(ERROR) << "Render("<< audio_data.size() << ", "
79 // << number_of_frames << ", "
80 // << audio_delay_milliseconds << ")";
81
82 base::AutoLock auto_lock(lock_);
83 if (stopped_)
84 return;
85
86 if (GetPlaybackRate() > 0.0f) {
87 // Adjust the playback delay.
88 base::Time current_time = base::Time::Now();
89
90 base::TimeDelta request_delay =
91 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
92
93 // Finally we need to adjust the delay according to playback rate.
94 if (GetPlaybackRate() != 1.0f) {
95 request_delay = base::TimeDelta::FromMicroseconds(
96 static_cast<int64>(ceil(request_delay.InMicroseconds() *
97 GetPlaybackRate())));
98 }
99
100 int buf_size = number_of_frames * bytes_per_frame_;
101 int bytes_per_sample = bytes_per_frame_ / audio_data.size();
102 DCHECK_EQ(bytes_per_sample, 2);
103 scoped_array<uint8> buf(new uint8[buf_size]);
104 uint32 filled = FillBuffer(buf.get(), buf_size, request_delay, false);
105 uint32 filled_frames = filled / bytes_per_frame_;
106 int stride = audio_data.size();
107 for (size_t i = 0; i < audio_data.size(); ++i) {
108 short* pSrc = reinterpret_cast<short*>(buf.get()) + i;
109 float* pDst = audio_data[i];
110
111 for (size_t j = 0; j < filled_frames; ++j) {
112 *pDst++ = *pSrc / 32768.0f;
113 pSrc += stride;
114 }
115 }
116 }
117 }
118
119 void AudioRendererImpl::SetAudioRendererSink(media::AudioRendererSink* audio_sin k)
120 {
121 if (audio_device_) {
122 audio_device_->Stop(); // ***************** NOT THREAD SAFE
123 }
124
125 audio_device_ = audio_sink;
114 } 126 }
115 127
116 void AudioRendererImpl::SetPlaybackRate(float rate) { 128 void AudioRendererImpl::SetPlaybackRate(float rate) {
117 DCHECK_LE(0.0f, rate); 129 DCHECK_LE(0.0f, rate);
118 130
119 base::AutoLock auto_lock(lock_); 131 base::AutoLock auto_lock(lock_);
120 // Handle the case where we stopped due to IO message loop dying. 132 // Handle the case where we stopped due to IO message loop dying.
121 if (stopped_) { 133 if (stopped_) {
122 AudioRendererBase::SetPlaybackRate(rate); 134 AudioRendererBase::SetPlaybackRate(rate);
123 return; 135 return;
124 } 136 }
125 137
126 // We have two cases here: 138 // We have two cases here:
127 // Play: GetPlaybackRate() == 0.0 && rate != 0.0 139 // Play: GetPlaybackRate() == 0.0 && rate != 0.0
128 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0 140 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0
129 if (GetPlaybackRate() == 0.0f && rate != 0.0f) { 141 if (GetPlaybackRate() == 0.0f && rate != 0.0f) {
130 ChildProcess::current()->io_message_loop()->PostTask( 142 render_loop_->PostTask(
131 FROM_HERE, 143 FROM_HERE,
132 NewRunnableMethod(this, &AudioRendererImpl::PlayTask)); 144 NewRunnableMethod(this, &AudioRendererImpl::PlayTask));
133 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) { 145 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) {
134 // Pause is easy, we can always pause. 146 // Pause is easy, we can always pause.
135 ChildProcess::current()->io_message_loop()->PostTask( 147 render_loop_->PostTask(
136 FROM_HERE, 148 FROM_HERE,
137 NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); 149 NewRunnableMethod(this, &AudioRendererImpl::PauseTask));
138 } 150 }
139 AudioRendererBase::SetPlaybackRate(rate); 151 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 } 152 }
147 153
148 void AudioRendererImpl::Pause(media::FilterCallback* callback) { 154 void AudioRendererImpl::Pause(media::FilterCallback* callback) {
149 AudioRendererBase::Pause(callback); 155 AudioRendererBase::Pause(callback);
150 base::AutoLock auto_lock(lock_); 156 base::AutoLock auto_lock(lock_);
151 if (stopped_) 157 if (stopped_)
152 return; 158 return;
153 159
154 ChildProcess::current()->io_message_loop()->PostTask( 160 render_loop_->PostTask(
155 FROM_HERE, 161 FROM_HERE,
156 NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); 162 NewRunnableMethod(this, &AudioRendererImpl::PauseTask));
157 } 163 }
158 164
159 void AudioRendererImpl::Seek(base::TimeDelta time, 165 void AudioRendererImpl::Seek(base::TimeDelta time,
160 const media::FilterStatusCB& cb) { 166 const media::FilterStatusCB& cb) {
161 AudioRendererBase::Seek(time, cb); 167 AudioRendererBase::Seek(time, cb);
162 base::AutoLock auto_lock(lock_); 168 base::AutoLock auto_lock(lock_);
163 if (stopped_) 169 if (stopped_)
164 return; 170 return;
165 171
166 ChildProcess::current()->io_message_loop()->PostTask( 172 render_loop_->PostTask(
167 FROM_HERE, 173 FROM_HERE,
168 NewRunnableMethod(this, &AudioRendererImpl::SeekTask)); 174 NewRunnableMethod(this, &AudioRendererImpl::SeekTask));
169 } 175 }
170 176
171 177
172 void AudioRendererImpl::Play(media::FilterCallback* callback) { 178 void AudioRendererImpl::Play(media::FilterCallback* callback) {
173 AudioRendererBase::Play(callback); 179 AudioRendererBase::Play(callback);
174 base::AutoLock auto_lock(lock_); 180 base::AutoLock auto_lock(lock_);
175 if (stopped_) 181 if (stopped_)
176 return; 182 return;
177 183
178 if (GetPlaybackRate() != 0.0f) { 184 if (GetPlaybackRate() != 0.0f) {
179 ChildProcess::current()->io_message_loop()->PostTask( 185 render_loop_->PostTask(
180 FROM_HERE, 186 FROM_HERE,
181 NewRunnableMethod(this, &AudioRendererImpl::PlayTask)); 187 NewRunnableMethod(this, &AudioRendererImpl::PlayTask));
182 } else { 188 } else {
183 ChildProcess::current()->io_message_loop()->PostTask( 189 render_loop_->PostTask(
184 FROM_HERE, 190 FROM_HERE,
185 NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); 191 NewRunnableMethod(this, &AudioRendererImpl::PauseTask));
186 } 192 }
187 } 193 }
188 194
189 void AudioRendererImpl::SetVolume(float volume) { 195 void AudioRendererImpl::SetVolume(float volume) {
190 base::AutoLock auto_lock(lock_); 196 base::AutoLock auto_lock(lock_);
191 if (stopped_) 197 if (stopped_)
192 return; 198 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 199
207 shared_memory_.reset(new base::SharedMemory(handle, false)); 200 if (audio_device_)
208 shared_memory_->Map(length); 201 audio_device_->SetVolume(volume);
209 shared_memory_size_ = length;
210 } 202 }
211 203
212 void AudioRendererImpl::CreateSocket(base::SyncSocket::Handle socket_handle) { 204 void AudioRendererImpl::InitializeTask(const AudioParameters& params) {
213 DCHECK_EQ(kLowLatency, latency_type_); 205 bytes_per_second_ = params.GetBytesPerSecond();
214 #if defined(OS_WIN) 206 bytes_per_frame_ = params.bits_per_sample * params.channels / 8;
215 DCHECK(socket_handle); 207
216 #else 208 audio_device_ = new AudioDevice(
217 DCHECK_GE(socket_handle, 0); 209 kBufferSize,
218 #endif 210 params.channels,
219 socket_.reset(new base::SyncSocket(socket_handle)); 211 params.sample_rate,
212 this);
220 } 213 }
221 214
222 void AudioRendererImpl::CreateAudioThread() { 215 void AudioRendererImpl::PlayTask() {
223 DCHECK_EQ(kLowLatency, latency_type_); 216 LOG(ERROR) << "PlayTask()";
224 audio_thread_.reset(
225 new base::DelegateSimpleThread(this, "renderer_audio_thread"));
226 audio_thread_->Start();
227 }
228 217
229 void AudioRendererImpl::OnLowLatencyCreated( 218 //Send(new AudioHostMsg_PlayStream(stream_id_));
230 base::SharedMemoryHandle handle, 219 if (audio_device_) {
231 base::SyncSocket::Handle socket_handle, 220 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 } 221 }
292 } 222 }
293 223
294 void AudioRendererImpl::OnVolume(double volume) { 224 void AudioRendererImpl::PauseTask() {
295 // TODO(hclam): decide whether we need to report the current volume to 225 LOG(ERROR) << "PauseTask()";
296 // pipeline.
297 }
298 226
299 void AudioRendererImpl::CreateStreamTask(const AudioParameters& audio_params) { 227 //Send(new AudioHostMsg_PauseStream(stream_id_));
300 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 228 if (audio_device_) {
301 229 audio_device_->Stop();
302 base::AutoLock auto_lock(lock_); 230 }
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 } 231 }
331 232
332 void AudioRendererImpl::SeekTask() { 233 void AudioRendererImpl::SeekTask() {
333 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 234 LOG(ERROR) << "SeekTask()";
334 235 if (audio_device_) {
236 audio_device_->Stop();
237 }
335 // We have to pause the audio stream before we can flush. 238 // We have to pause the audio stream before we can flush.
336 Send(new AudioHostMsg_PauseStream(stream_id_)); 239 //Send(new AudioHostMsg_PauseStream(stream_id_));
337 Send(new AudioHostMsg_FlushStream(stream_id_)); 240 //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 // During shutdown this may be NULL; don't worry about deregistering in that
348 // case.
349 if (ChildProcess::current())
350 ChildProcess::current()->io_message_loop()->RemoveDestructionObserver(this);
351 stream_id_ = 0;
352 }
353
354 void AudioRendererImpl::SetVolumeTask(double volume) {
355 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
356
357 base::AutoLock auto_lock(lock_);
358 if (stopped_)
359 return;
360 Send(new AudioHostMsg_SetVolume(stream_id_, volume));
361 }
362
363 void AudioRendererImpl::NotifyPacketReadyTask() {
364 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
365 DCHECK_EQ(kHighLatency, latency_type_);
366
367 base::AutoLock auto_lock(lock_);
368 if (stopped_)
369 return;
370 if (pending_request_ && GetPlaybackRate() > 0.0f) {
371 DCHECK(shared_memory_.get());
372
373 // Adjust the playback delay.
374 base::Time current_time = base::Time::Now();
375
376 base::TimeDelta request_delay =
377 ConvertToDuration(request_buffers_state_.total_bytes());
378
379 // Add message delivery delay.
380 if (current_time > request_buffers_state_.timestamp) {
381 base::TimeDelta receive_latency =
382 current_time - request_buffers_state_.timestamp;
383
384 // If the receive latency is too much it may offset all the delay.
385 if (receive_latency >= request_delay) {
386 request_delay = base::TimeDelta();
387 } else {
388 request_delay -= receive_latency;
389 }
390 }
391
392 // Finally we need to adjust the delay according to playback rate.
393 if (GetPlaybackRate() != 1.0f) {
394 request_delay = base::TimeDelta::FromMicroseconds(
395 static_cast<int64>(ceil(request_delay.InMicroseconds() *
396 GetPlaybackRate())));
397 }
398
399 uint32 filled = FillBuffer(static_cast<uint8*>(shared_memory_->memory()),
400 shared_memory_size_, request_delay,
401 request_buffers_state_.pending_bytes == 0);
402 pending_request_ = false;
403 // Then tell browser process we are done filling into the buffer.
404 Send(new AudioHostMsg_NotifyPacketReady(stream_id_, filled));
405 }
406 } 241 }
407 242
408 void AudioRendererImpl::WillDestroyCurrentMessageLoop() { 243 void AudioRendererImpl::WillDestroyCurrentMessageLoop() {
409 DCHECK(!ChildProcess::current() || // During shutdown. 244 DCHECK(!ChildProcess::current() || // During shutdown.
410 (MessageLoop::current() == 245 (MessageLoop::current() ==
411 ChildProcess::current()->io_message_loop())); 246 ChildProcess::current()->io_message_loop()));
412 247
413 // We treat the IO loop going away the same as stopping. 248 // We treat the IO loop going away the same as stopping.
414 base::AutoLock auto_lock(lock_); 249 base::AutoLock auto_lock(lock_);
415 if (stopped_) 250 if (stopped_)
416 return; 251 return;
417 252
418 stopped_ = true; 253 stopped_ = true;
419 DestroyTask(); 254 if (audio_device_) {
420 } 255 audio_device_->Stop(); // ***************** NOT THREAD SAFE
421 256 audio_device_ = NULL;
422 // Our audio thread runs here. We receive requests for more data and send it
423 // on this thread.
424 void AudioRendererImpl::Run() {
425 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
426
427 int bytes;
428 while (sizeof(bytes) == socket_->Receive(&bytes, sizeof(bytes))) {
429 LOG(ERROR) << "+++ bytes: " << bytes;
430 if (bytes == media::AudioOutputController::kPauseMark)
431 continue;
432 else if (bytes < 0)
433 break;
434 base::AutoLock auto_lock(lock_);
435 if (stopped_)
436 break;
437 float playback_rate = GetPlaybackRate();
438 if (playback_rate <= 0.0f)
439 continue;
440 DCHECK(shared_memory_.get());
441 base::TimeDelta request_delay = ConvertToDuration(bytes);
442 // We need to adjust the delay according to playback rate.
443 if (playback_rate != 1.0f) {
444 request_delay = base::TimeDelta::FromMicroseconds(
445 static_cast<int64>(ceil(request_delay.InMicroseconds() *
446 playback_rate)));
447 }
448 FillBuffer(static_cast<uint8*>(shared_memory_->memory()),
449 shared_memory_size_,
450 request_delay,
451 true /* buffers empty */);
452 } 257 }
453 } 258 }
454
455 void AudioRendererImpl::Send(IPC::Message* message) {
456 filter_->Send(message);
457 }
OLDNEW
« no previous file with comments | « content/renderer/media/audio_renderer_impl.h ('k') | content/renderer/render_audiosourceprovider.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698