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

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

Issue 10560038: Change the way we are stopping audio stream on Mac once again. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 years, 6 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 <CoreServices/CoreServices.h> 7 #include <CoreServices/CoreServices.h>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 packet_size_(params.GetBytesPerBuffer()), 53 packet_size_(params.GetBytesPerBuffer()),
54 silence_bytes_(0), 54 silence_bytes_(0),
55 volume_(1), 55 volume_(1),
56 pending_bytes_(0), 56 pending_bytes_(0),
57 num_source_channels_(params.channels()), 57 num_source_channels_(params.channels()),
58 source_layout_(params.channel_layout()), 58 source_layout_(params.channel_layout()),
59 num_core_channels_(0), 59 num_core_channels_(0),
60 should_swizzle_(false), 60 should_swizzle_(false),
61 should_down_mix_(false), 61 should_down_mix_(false),
62 stopped_event_(true /* manual reset */, false /* initial state */), 62 stopped_event_(true /* manual reset */, false /* initial state */),
63 num_buffers_left_(kNumBuffers) { 63 stop_requested_(false) {
64 // We must have a manager. 64 // We must have a manager.
65 DCHECK(manager_); 65 DCHECK(manager_);
66 // A frame is one sample across all channels. In interleaved audio the per 66 // A frame is one sample across all channels. In interleaved audio the per
67 // frame fields identify the set of n |channels|. In uncompressed audio, a 67 // frame fields identify the set of n |channels|. In uncompressed audio, a
68 // packet is always one frame. 68 // packet is always one frame.
69 format_.mSampleRate = params.sample_rate(); 69 format_.mSampleRate = params.sample_rate();
70 format_.mFormatID = kAudioFormatLinearPCM; 70 format_.mFormatID = kAudioFormatLinearPCM;
71 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked; 71 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked;
72 format_.mBitsPerChannel = params.bits_per_sample(); 72 format_.mBitsPerChannel = params.bits_per_sample();
73 format_.mChannelsPerFrame = params.channels(); 73 format_.mChannelsPerFrame = params.channels();
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 core_channel_orderings_[input_channel] == kEmptyChannel && 372 core_channel_orderings_[input_channel] == kEmptyChannel &&
373 kChannelOrderings[source_layout_][input_channel] > kEmptyChannel && 373 kChannelOrderings[source_layout_][input_channel] > kEmptyChannel &&
374 kChannelOrderings[source_layout_][output_channel] == kEmptyChannel) { 374 kChannelOrderings[source_layout_][output_channel] == kEmptyChannel) {
375 channel_remap_[core_channel_orderings_[output_channel]] = 375 channel_remap_[core_channel_orderings_[output_channel]] =
376 kChannelOrderings[source_layout_][input_channel]; 376 kChannelOrderings[source_layout_][input_channel];
377 return true; 377 return true;
378 } 378 }
379 return false; 379 return false;
380 } 380 }
381 381
382 void PCMQueueOutAudioOutputStream::IsRunningCallback(
383 void* p_this,
384 AudioQueueRef queue,
385 AudioQueuePropertyID inID) {
386 PCMQueueOutAudioOutputStream* audio_stream =
387 static_cast<PCMQueueOutAudioOutputStream*>(p_this);
388 UInt32 running = 0;
389 UInt32 size = sizeof(running);
390 OSStatus err = AudioQueueGetProperty(queue,
391 kAudioQueueProperty_IsRunning,
392 &running,
393 &size);
394 if (err) {
395 audio_stream->HandleError(err);
396 return;
397 }
398 if (!running) {
399 // Remove property listener, we don't need it anymore.
400 OSStatus err = AudioQueueRemovePropertyListener(
401 queue,
402 kAudioQueueProperty_IsRunning,
403 PCMQueueOutAudioOutputStream::IsRunningCallback,
404 audio_stream);
405 if (err != noErr)
406 audio_stream->HandleError(err);
407
408 // Ok, finally signal that stream is not running.
409 audio_stream->stopped_event_.Signal();
410 }
411 }
412
382 // Note to future hackers of this function: Do not add locks to this function 413 // Note to future hackers of this function: Do not add locks to this function
383 // that are held through any calls made back into AudioQueue APIs, or other 414 // that are held through any calls made back into AudioQueue APIs, or other
384 // OS audio functions. This is because the OS dispatch may grab external 415 // OS audio functions. This is because the OS dispatch may grab external
385 // locks, or possibly re-enter this function which can lead to a deadlock. 416 // locks, or possibly re-enter this function which can lead to a deadlock.
386 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this, 417 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this,
387 AudioQueueRef queue, 418 AudioQueueRef queue,
388 AudioQueueBufferRef buffer) { 419 AudioQueueBufferRef buffer) {
389 TRACE_EVENT0("audio", "PCMQueueOutAudioOutputStream::RenderCallback"); 420 TRACE_EVENT0("audio", "PCMQueueOutAudioOutputStream::RenderCallback");
390 421
391 PCMQueueOutAudioOutputStream* audio_stream = 422 PCMQueueOutAudioOutputStream* audio_stream =
392 static_cast<PCMQueueOutAudioOutputStream*>(p_this); 423 static_cast<PCMQueueOutAudioOutputStream*>(p_this);
393 424
394 // Call the audio source to fill the free buffer with data. Not having a 425 // Call the audio source to fill the free buffer with data. Not having a
395 // source means that the queue has been stopped. 426 // source means that the queue has been stopped.
396 AudioSourceCallback* source = audio_stream->GetSource(); 427 AudioSourceCallback* source = audio_stream->GetSource();
397 if (!source) { 428 if (!source) {
398 // PCMQueueOutAudioOutputStream::Stop() is waiting for callback to 429 // PCMQueueOutAudioOutputStream::Stop() is waiting for callback to
399 // stop the stream and signal when all callbacks are done. 430 // stop the stream and signal when all activity ceased (we probably
400 // (we probably can stop the stream there, but it is better to have 431 // can stop the stream there, but it is better to have all the
401 // all the complex logic in one place; stopping latency is not very 432 // complex logic in one place; stopping latency is not very important
402 // important if you reuse audio stream in the mixer and not close it 433 // if you reuse audio stream in the mixer and not close it immediately).
403 // immediately). 434 if (!audio_stream->stop_requested_) {
404 --audio_stream->num_buffers_left_; 435 audio_stream->stop_requested_ = true;
scherkus (not reviewing) 2012/06/18 19:40:53 do we need to reset this to false at some point in
enal1 2012/06/18 19:58:47 When starting the stream. in PCMQueueOutAudioOutpu
405 if (audio_stream->num_buffers_left_ == kNumBuffers - 1) { 436 // Before actually stopping the stream, register callback that
406 // First buffer after stop requested, stop the queue. 437 // OS would call when status of "is running" property changes.
407 OSStatus err = AudioQueueStop(audio_stream->audio_queue_, true); 438 // This way we (hopefully) would know when stream is actually
439 // stopped and it is safe to dispose it.
440 OSStatus err = AudioQueueAddPropertyListener(
441 queue,
scherkus (not reviewing) 2012/06/18 19:40:53 minor nit: in line 448 you use audio_stream->audio
enal1 2012/06/18 19:58:47 Done.
442 kAudioQueueProperty_IsRunning,
443 PCMQueueOutAudioOutputStream::IsRunningCallback,
444 audio_stream);
408 if (err != noErr) 445 if (err != noErr)
409 audio_stream->HandleError(err); 446 audio_stream->HandleError(err);
410 } 447 // Now stop the queue.
411 if (audio_stream->num_buffers_left_ == 0) { 448 err = AudioQueueStop(audio_stream->audio_queue_, true);
412 // Now we finally saw all the buffers. 449 if (err != noErr)
413 // Signal that stopping is complete. 450 audio_stream->HandleError(err);
414 // Should never touch audio_stream after signaling as it
415 // can be deleted at any moment.
416 audio_stream->stopped_event_.Signal();
417 } 451 }
418 return; 452 return;
419 } 453 }
420 454
421 // Adjust the number of pending bytes by subtracting the amount played. 455 // Adjust the number of pending bytes by subtracting the amount played.
422 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer) 456 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer)
423 audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize; 457 audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize;
424 uint32 capacity = buffer->mAudioDataBytesCapacity; 458 uint32 capacity = buffer->mAudioDataBytesCapacity;
425 // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState. 459 // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState.
426 uint32 filled = source->OnMoreData( 460 uint32 filled = source->OnMoreData(
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) { 536 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) {
503 DCHECK(callback); 537 DCHECK(callback);
504 DLOG_IF(ERROR, !audio_queue_) << "Open() has not been called successfully"; 538 DLOG_IF(ERROR, !audio_queue_) << "Open() has not been called successfully";
505 if (!audio_queue_) 539 if (!audio_queue_)
506 return; 540 return;
507 541
508 OSStatus err = noErr; 542 OSStatus err = noErr;
509 SetSource(callback); 543 SetSource(callback);
510 pending_bytes_ = 0; 544 pending_bytes_ = 0;
511 stopped_event_.Reset(); 545 stopped_event_.Reset();
512 num_buffers_left_ = kNumBuffers; 546 stop_requested_ = false;
513 // Ask the source to pre-fill all our buffers before playing. 547 // Ask the source to pre-fill all our buffers before playing.
514 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { 548 for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
515 buffer_[ix]->mAudioDataByteSize = 0; 549 buffer_[ix]->mAudioDataByteSize = 0;
516 // Caller waits for 1st packet to become available, but not for others, 550 // Caller waits for 1st packet to become available, but not for others,
517 // so we wait for them here. 551 // so we wait for them here.
518 if (ix != 0) { 552 if (ix != 0) {
519 AudioSourceCallback* source = GetSource(); 553 AudioSourceCallback* source = GetSource();
520 if (source) 554 if (source)
521 source->WaitTillDataReady(); 555 source->WaitTillDataReady();
522 } 556 }
(...skipping 20 matching lines...) Expand all
543 source_ = source; 577 source_ = source;
544 } 578 }
545 579
546 AudioOutputStream::AudioSourceCallback* 580 AudioOutputStream::AudioSourceCallback*
547 PCMQueueOutAudioOutputStream::GetSource() { 581 PCMQueueOutAudioOutputStream::GetSource() {
548 base::AutoLock lock(source_lock_); 582 base::AutoLock lock(source_lock_);
549 return source_; 583 return source_;
550 } 584 }
551 585
552 } // namespace media 586 } // namespace media
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