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)), |
| 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 |