Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/audio_output_dispatcher.h" | 5 #include "media/audio/audio_output_dispatcher.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/time.h" | 10 #include "base/time.h" |
| 11 #include "media/audio/audio_io.h" | 11 #include "media/audio/audio_io.h" |
| 12 | 12 |
| 13 AudioOutputDispatcher::AudioOutputDispatcher( | 13 AudioOutputDispatcher::AudioOutputDispatcher( |
| 14 AudioManager* audio_manager, const AudioParameters& params, | 14 AudioManager* audio_manager, const AudioParameters& params, |
| 15 int close_delay_ms) | 15 int close_delay_ms) |
| 16 : audio_manager_(audio_manager), | 16 : audio_manager_(audio_manager), |
| 17 message_loop_(audio_manager->GetMessageLoop()), | 17 message_loop_(audio_manager->GetMessageLoop()), |
| 18 params_(params), | 18 params_(params), |
| 19 pause_delay_milliseconds_(2 * params.samples_per_packet * | 19 pause_delay_milliseconds_(2 * params.samples_per_packet * |
| 20 base::Time::kMillisecondsPerSecond / params.sample_rate), | 20 base::Time::kMillisecondsPerSecond / params.sample_rate), |
| 21 paused_proxies_(0), | 21 paused_proxies_(0), |
| 22 ALLOW_THIS_IN_INITIALIZER_LIST(close_timer_(FROM_HERE, | 22 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)), |
|
henrika (OOO until Aug 14)
2011/12/07 10:08:34
Not sure why this is needed.
tommi (sloooow) - chröme
2011/12/07 12:26:44
It allows |this| to be used in an initializer list
henrika (OOO until Aug 14)
2011/12/07 12:48:01
I meant the weak pointer.
tommi (sloooow) - chröme
2011/12/07 14:46:23
Ah. Here's the comment from the header file:
/
| |
| 23 close_timer_(FROM_HERE, | |
| 23 base::TimeDelta::FromMilliseconds(close_delay_ms), | 24 base::TimeDelta::FromMilliseconds(close_delay_ms), |
| 24 this, &AudioOutputDispatcher::ClosePendingStreams)) { | 25 weak_this_.GetWeakPtr(), |
| 26 &AudioOutputDispatcher::ClosePendingStreams) { | |
| 27 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 25 } | 28 } |
| 26 | 29 |
| 27 AudioOutputDispatcher::~AudioOutputDispatcher() { | 30 AudioOutputDispatcher::~AudioOutputDispatcher() { |
| 31 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 28 } | 32 } |
| 29 | 33 |
| 30 bool AudioOutputDispatcher::StreamOpened() { | 34 bool AudioOutputDispatcher::StreamOpened() { |
| 31 DCHECK_EQ(MessageLoop::current(), message_loop_); | 35 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 32 paused_proxies_++; | 36 paused_proxies_++; |
| 33 | 37 |
| 34 // Ensure that there is at least one open stream. | 38 // Ensure that there is at least one open stream. |
| 35 if (idle_streams_.empty() && !CreateAndOpenStream()) { | 39 if (idle_streams_.empty() && !CreateAndOpenStream()) { |
| 36 return false; | 40 return false; |
| 37 } | 41 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 51 AudioOutputStream* stream = idle_streams_.back(); | 55 AudioOutputStream* stream = idle_streams_.back(); |
| 52 idle_streams_.pop_back(); | 56 idle_streams_.pop_back(); |
| 53 | 57 |
| 54 DCHECK_GT(paused_proxies_, 0u); | 58 DCHECK_GT(paused_proxies_, 0u); |
| 55 paused_proxies_--; | 59 paused_proxies_--; |
| 56 | 60 |
| 57 close_timer_.Reset(); | 61 close_timer_.Reset(); |
| 58 | 62 |
| 59 // Schedule task to allocate streams for other proxies if we need to. | 63 // Schedule task to allocate streams for other proxies if we need to. |
| 60 message_loop_->PostTask(FROM_HERE, base::Bind( | 64 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 61 &AudioOutputDispatcher::OpenTask, this)); | 65 &AudioOutputDispatcher::OpenTask, weak_this_.GetWeakPtr())); |
| 62 | 66 |
| 63 return stream; | 67 return stream; |
| 64 } | 68 } |
| 65 | 69 |
| 66 void AudioOutputDispatcher::StreamStopped(AudioOutputStream* stream) { | 70 void AudioOutputDispatcher::StreamStopped(AudioOutputStream* stream) { |
| 67 DCHECK_EQ(MessageLoop::current(), message_loop_); | 71 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 68 | 72 |
| 69 paused_proxies_++; | 73 paused_proxies_++; |
| 70 | 74 |
| 71 pausing_streams_.push_front(stream); | 75 pausing_streams_.push_front(stream); |
| 72 | 76 |
| 73 // Don't recycle stream until two buffers worth of time has elapsed. | 77 // Don't recycle stream until two buffers worth of time has elapsed. |
| 74 message_loop_->PostDelayedTask( | 78 message_loop_->PostDelayedTask( |
| 75 FROM_HERE, | 79 FROM_HERE, |
| 76 base::Bind(&AudioOutputDispatcher::StopStreamTask, this), | 80 base::Bind(&AudioOutputDispatcher::StopStreamTask, |
| 81 weak_this_.GetWeakPtr()), | |
| 77 pause_delay_milliseconds_); | 82 pause_delay_milliseconds_); |
| 78 } | 83 } |
| 79 | 84 |
| 80 void AudioOutputDispatcher::StopStreamTask() { | 85 void AudioOutputDispatcher::StopStreamTask() { |
| 86 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 87 | |
| 81 if (pausing_streams_.empty()) | 88 if (pausing_streams_.empty()) |
| 82 return; | 89 return; |
| 90 | |
| 83 AudioOutputStream* stream = pausing_streams_.back(); | 91 AudioOutputStream* stream = pausing_streams_.back(); |
| 84 pausing_streams_.pop_back(); | 92 pausing_streams_.pop_back(); |
| 85 idle_streams_.push_back(stream); | 93 idle_streams_.push_back(stream); |
| 86 close_timer_.Reset(); | 94 close_timer_.Reset(); |
| 87 } | 95 } |
| 88 | 96 |
| 89 void AudioOutputDispatcher::StreamClosed() { | 97 void AudioOutputDispatcher::StreamClosed() { |
| 90 DCHECK_EQ(MessageLoop::current(), message_loop_); | 98 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 91 | 99 |
| 92 while (!pausing_streams_.empty()) { | 100 while (!pausing_streams_.empty()) { |
| 93 idle_streams_.push_back(pausing_streams_.back()); | 101 idle_streams_.push_back(pausing_streams_.back()); |
| 94 pausing_streams_.pop_back(); | 102 pausing_streams_.pop_back(); |
| 95 } | 103 } |
| 96 | 104 |
| 97 DCHECK_GT(paused_proxies_, 0u); | 105 DCHECK_GT(paused_proxies_, 0u); |
| 98 paused_proxies_--; | 106 paused_proxies_--; |
| 99 | 107 |
| 100 while (idle_streams_.size() > paused_proxies_) { | 108 while (idle_streams_.size() > paused_proxies_) { |
| 101 idle_streams_.back()->Close(); | 109 idle_streams_.back()->Close(); |
| 102 idle_streams_.pop_back(); | 110 idle_streams_.pop_back(); |
| 103 } | 111 } |
| 104 } | 112 } |
| 105 | 113 |
| 114 void AudioOutputDispatcher::Shutdown() { | |
| 115 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 116 | |
| 117 // Cancel any pending tasks to close paused streams or create new ones. | |
| 118 weak_this_.InvalidateWeakPtrs(); | |
| 119 | |
| 120 // No AudioOutputProxy objects should hold a reference to us when we get | |
| 121 // to this stage. | |
| 122 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference"; | |
| 123 | |
| 124 AudioOutputStreamList::iterator it = idle_streams_.begin(); | |
| 125 for (; it != idle_streams_.end(); ++it) | |
| 126 (*it)->Close(); | |
| 127 idle_streams_.clear(); | |
| 128 | |
| 129 it = pausing_streams_.begin(); | |
| 130 for (; it != pausing_streams_.end(); ++it) | |
| 131 (*it)->Close(); | |
| 132 pausing_streams_.clear(); | |
| 133 } | |
| 134 | |
| 106 MessageLoop* AudioOutputDispatcher::message_loop() { | 135 MessageLoop* AudioOutputDispatcher::message_loop() { |
| 107 return message_loop_; | 136 return message_loop_; |
| 108 } | 137 } |
| 109 | 138 |
| 110 bool AudioOutputDispatcher::CreateAndOpenStream() { | 139 bool AudioOutputDispatcher::CreateAndOpenStream() { |
| 111 AudioOutputStream* stream = | 140 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_); |
| 112 audio_manager_->MakeAudioOutputStream(params_); | 141 if (!stream) |
| 113 if (!stream) { | |
| 114 return false; | 142 return false; |
| 115 } | 143 |
| 116 if (!stream->Open()) { | 144 if (!stream->Open()) { |
| 117 stream->Close(); | 145 stream->Close(); |
| 118 return false; | 146 return false; |
| 119 } | 147 } |
| 120 idle_streams_.push_back(stream); | 148 idle_streams_.push_back(stream); |
| 121 return true; | 149 return true; |
| 122 } | 150 } |
| 123 | 151 |
| 124 void AudioOutputDispatcher::OpenTask() { | 152 void AudioOutputDispatcher::OpenTask() { |
| 125 // Make sure that we have at least one stream allocated if there | 153 // Make sure that we have at least one stream allocated if there |
| 126 // are paused streams. | 154 // are paused streams. |
| 127 if (paused_proxies_ > 0 && idle_streams_.empty() && | 155 if (paused_proxies_ > 0 && idle_streams_.empty() && |
| 128 pausing_streams_.empty()) { | 156 pausing_streams_.empty()) { |
| 129 CreateAndOpenStream(); | 157 CreateAndOpenStream(); |
| 130 } | 158 } |
| 131 | 159 |
| 132 close_timer_.Reset(); | 160 close_timer_.Reset(); |
| 133 } | 161 } |
| 134 | 162 |
| 135 // This method is called by |close_timer_|. | 163 // This method is called by |close_timer_|. |
| 136 void AudioOutputDispatcher::ClosePendingStreams() { | 164 void AudioOutputDispatcher::ClosePendingStreams() { |
| 165 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 166 | |
| 137 while (!idle_streams_.empty()) { | 167 while (!idle_streams_.empty()) { |
| 138 idle_streams_.back()->Close(); | 168 idle_streams_.back()->Close(); |
| 139 idle_streams_.pop_back(); | 169 idle_streams_.pop_back(); |
| 140 } | 170 } |
| 141 } | 171 } |
| OLD | NEW |