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

Side by Side Diff: media/audio/mac/audio_output_mac.cc

Issue 7888055: Add a lock around getting and setting of source_ to avoid possible compiler reorderings. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebased Created 9 years, 3 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
« no previous file with comments | « media/audio/mac/audio_output_mac.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "media/audio/mac/audio_output_mac.h" 5 #include "media/audio/mac/audio_output_mac.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 silence_bytes_ = format_.mBytesPerFrame * params.sample_rate * 6 / 1000; 84 silence_bytes_ = format_.mBytesPerFrame * params.sample_rate * 6 / 1000;
85 } 85 }
86 86
87 PCMQueueOutAudioOutputStream::~PCMQueueOutAudioOutputStream() { 87 PCMQueueOutAudioOutputStream::~PCMQueueOutAudioOutputStream() {
88 } 88 }
89 89
90 void PCMQueueOutAudioOutputStream::HandleError(OSStatus err) { 90 void PCMQueueOutAudioOutputStream::HandleError(OSStatus err) {
91 // source_ can be set to NULL from another thread. We need to cache its 91 // source_ can be set to NULL from another thread. We need to cache its
92 // pointer while we operate here. Note that does not mean that the source 92 // pointer while we operate here. Note that does not mean that the source
93 // has been destroyed. 93 // has been destroyed.
94 AudioSourceCallback* source = source_; 94 AudioSourceCallback* source = GetSource();
95 if (source) 95 if (source)
96 source->OnError(this, static_cast<int>(err)); 96 source->OnError(this, static_cast<int>(err));
97 NOTREACHED() << "error code " << err; 97 NOTREACHED() << "error code " << err;
98 } 98 }
99 99
100 bool PCMQueueOutAudioOutputStream::Open() { 100 bool PCMQueueOutAudioOutputStream::Open() {
101 // Get the default device id. 101 // Get the default device id.
102 AudioObjectID device_id = 0; 102 AudioObjectID device_id = 0;
103 AudioObjectPropertyAddress property_address = { 103 AudioObjectPropertyAddress property_address = {
104 kAudioHardwarePropertyDefaultOutputDevice, 104 kAudioHardwarePropertyDefaultOutputDevice,
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 format_.mChannelsPerFrame = num_core_channels_; 150 format_.mChannelsPerFrame = num_core_channels_;
151 format_.mBytesPerFrame = (format_.mBitsPerChannel >> 3) * 151 format_.mBytesPerFrame = (format_.mBitsPerChannel >> 3) *
152 format_.mChannelsPerFrame; 152 format_.mChannelsPerFrame;
153 format_.mBytesPerPacket = format_.mBytesPerFrame * format_.mFramesPerPacket; 153 format_.mBytesPerPacket = format_.mBytesPerFrame * format_.mFramesPerPacket;
154 } else { 154 } else {
155 should_down_mix_ = false; 155 should_down_mix_ = false;
156 } 156 }
157 // Create the actual queue object and let the OS use its own thread to 157 // Create the actual queue object and let the OS use its own thread to
158 // run its CFRunLoop. 158 // run its CFRunLoop.
159 err = AudioQueueNewOutput(&format_, RenderCallback, this, NULL, 159 err = AudioQueueNewOutput(&format_, RenderCallback, this, NULL,
160 kCFRunLoopCommonModes, 0, &audio_queue_); 160 kCFRunLoopCommonModes, 0, &audio_queue_);
161 if (err != noErr) { 161 if (err != noErr) {
162 HandleError(err); 162 HandleError(err);
163 return false; 163 return false;
164 } 164 }
165 // Allocate the hardware-managed buffers. 165 // Allocate the hardware-managed buffers.
166 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { 166 for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
167 err = AudioQueueAllocateBuffer(audio_queue_, packet_size_, &buffer_[ix]); 167 err = AudioQueueAllocateBuffer(audio_queue_, packet_size_, &buffer_[ix]);
168 if (err != noErr) { 168 if (err != noErr) {
169 HandleError(err); 169 HandleError(err);
170 return false; 170 return false;
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 HandleError(err); 307 HandleError(err);
308 } 308 }
309 // Inform the audio manager that we have been closed. This can cause our 309 // Inform the audio manager that we have been closed. This can cause our
310 // destruction. 310 // destruction.
311 manager_->ReleaseOutputStream(this); 311 manager_->ReleaseOutputStream(this);
312 } 312 }
313 313
314 void PCMQueueOutAudioOutputStream::Stop() { 314 void PCMQueueOutAudioOutputStream::Stop() {
315 // We request a synchronous stop, so the next call can take some time. In 315 // We request a synchronous stop, so the next call can take some time. In
316 // the windows implementation we block here as well. 316 // the windows implementation we block here as well.
317 source_ = NULL; 317 SetSource(NULL);
318
318 // We set the source to null to signal to the data queueing thread it can stop 319 // We set the source to null to signal to the data queueing thread it can stop
319 // queueing data, however at most one callback might still be in flight which 320 // queueing data, however at most one callback might still be in flight which
320 // could attempt to enqueue right after the next call. Rather that trying to 321 // could attempt to enqueue right after the next call. Rather that trying to
321 // use a lock we rely on the internal Mac queue lock so the enqueue might 322 // use a lock we rely on the internal Mac queue lock so the enqueue might
322 // succeed or might fail but it won't crash or leave the queue itself in an 323 // succeed or might fail but it won't crash or leave the queue itself in an
323 // inconsistent state. 324 // inconsistent state.
324 OSStatus err = AudioQueueStop(audio_queue_, true); 325 OSStatus err = AudioQueueStop(audio_queue_, true);
325 if (err != noErr) 326 if (err != noErr)
326 HandleError(err); 327 HandleError(err);
327 } 328 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 core_channel_orderings_[input_channel] == kEmptyChannel && 372 core_channel_orderings_[input_channel] == kEmptyChannel &&
372 kChannelOrderings[source_layout_][input_channel] > kEmptyChannel && 373 kChannelOrderings[source_layout_][input_channel] > kEmptyChannel &&
373 kChannelOrderings[source_layout_][output_channel] == kEmptyChannel) { 374 kChannelOrderings[source_layout_][output_channel] == kEmptyChannel) {
374 channel_remap_[core_channel_orderings_[output_channel]] = 375 channel_remap_[core_channel_orderings_[output_channel]] =
375 kChannelOrderings[source_layout_][input_channel]; 376 kChannelOrderings[source_layout_][input_channel];
376 return true; 377 return true;
377 } 378 }
378 return false; 379 return false;
379 } 380 }
380 381
381 // Note to future hackers of this function: Do not add locks here because we 382 // Note to future hackers of this function: Do not add locks to this function
382 // call out to third party source that might do crazy things including adquire 383 // that are held through any calls made back into AudioQueue APIs, or other
383 // external locks or somehow re-enter here because its legal for them to call 384 // OS audio functions. This is because the OS dispatch may grab external
384 // some audio functions. 385 // locks, or possibly re-enter this function which can lead to a deadlock.
385 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this, 386 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this,
386 AudioQueueRef queue, 387 AudioQueueRef queue,
387 AudioQueueBufferRef buffer) { 388 AudioQueueBufferRef buffer) {
388 TRACE_EVENT0("audio", "PCMQueueOutAudioOutputStream::RenderCallback"); 389 TRACE_EVENT0("audio", "PCMQueueOutAudioOutputStream::RenderCallback");
389 390
390 PCMQueueOutAudioOutputStream* audio_stream = 391 PCMQueueOutAudioOutputStream* audio_stream =
391 static_cast<PCMQueueOutAudioOutputStream*>(p_this); 392 static_cast<PCMQueueOutAudioOutputStream*>(p_this);
392 // Call the audio source to fill the free buffer with data. Not having a 393 // Call the audio source to fill the free buffer with data. Not having a
393 // source means that the queue has been closed. This is not an error. 394 // source means that the queue has been closed. This is not an error.
394 AudioSourceCallback* source = audio_stream->source_; 395 AudioSourceCallback* source = audio_stream->GetSource();
395 if (!source) 396 if (!source)
396 return; 397 return;
397 398
398 // Adjust the number of pending bytes by subtracting the amount played. 399 // Adjust the number of pending bytes by subtracting the amount played.
399 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer) 400 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer)
400 audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize; 401 audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize;
401 uint32 capacity = buffer->mAudioDataBytesCapacity; 402 uint32 capacity = buffer->mAudioDataBytesCapacity;
402 // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState. 403 // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState.
403 uint32 filled = source->OnMoreData( 404 uint32 filled = source->OnMoreData(
404 audio_stream, reinterpret_cast<uint8*>(buffer->mAudioData), capacity, 405 audio_stream, reinterpret_cast<uint8*>(buffer->mAudioData), capacity,
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer) 461 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer)
461 audio_stream->pending_bytes_ += filled; 462 audio_stream->pending_bytes_ += filled;
462 if (NULL == queue) 463 if (NULL == queue)
463 return; 464 return;
464 // Queue the audio data to the audio driver. 465 // Queue the audio data to the audio driver.
465 OSStatus err = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL); 466 OSStatus err = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL);
466 if (err != noErr) { 467 if (err != noErr) {
467 if (err == kAudioQueueErr_EnqueueDuringReset) { 468 if (err == kAudioQueueErr_EnqueueDuringReset) {
468 // This is the error you get if you try to enqueue a buffer and the 469 // This is the error you get if you try to enqueue a buffer and the
469 // queue has been closed. Not really a problem if indeed the queue 470 // queue has been closed. Not really a problem if indeed the queue
470 // has been closed. 471 // has been closed. We recheck the value of source now to see if it has
471 if (!audio_stream->source_) 472 // indeed been closed.
473 if (!audio_stream->GetSource())
472 return; 474 return;
473 } 475 }
474 audio_stream->HandleError(err); 476 audio_stream->HandleError(err);
475 } 477 }
476 } 478 }
477 479
478 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) { 480 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) {
479 DCHECK(callback); 481 DCHECK(callback);
480 OSStatus err = noErr; 482 OSStatus err = noErr;
481 source_ = callback; 483 SetSource(callback);
482 pending_bytes_ = 0; 484 pending_bytes_ = 0;
483 // Ask the source to pre-fill all our buffers before playing. 485 // Ask the source to pre-fill all our buffers before playing.
484 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { 486 for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
485 buffer_[ix]->mAudioDataByteSize = 0; 487 buffer_[ix]->mAudioDataByteSize = 0;
486 RenderCallback(this, NULL, buffer_[ix]); 488 RenderCallback(this, NULL, buffer_[ix]);
487 } 489 }
488 490
489 // Queue the buffers to the audio driver, sounds starts now. 491 // Queue the buffers to the audio driver, sounds starts now.
490 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { 492 for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
491 err = AudioQueueEnqueueBuffer(audio_queue_, buffer_[ix], 0, NULL); 493 err = AudioQueueEnqueueBuffer(audio_queue_, buffer_[ix], 0, NULL);
492 if (err != noErr) { 494 if (err != noErr) {
493 HandleError(err); 495 HandleError(err);
494 return; 496 return;
495 } 497 }
496 } 498 }
497 err = AudioQueueStart(audio_queue_, NULL); 499 err = AudioQueueStart(audio_queue_, NULL);
498 if (err != noErr) { 500 if (err != noErr) {
499 HandleError(err); 501 HandleError(err);
500 return; 502 return;
501 } 503 }
502 } 504 }
505
506 void PCMQueueOutAudioOutputStream::SetSource(AudioSourceCallback* source) {
507 base::AutoLock lock(source_lock_);
508 source_ = source;
509 }
510
511 AudioOutputStream::AudioSourceCallback*
512 PCMQueueOutAudioOutputStream::GetSource() {
513 base::AutoLock lock(source_lock_);
514 return source_;
515 }
OLDNEW
« no previous file with comments | « media/audio/mac/audio_output_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698