OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "media/audio/audio_output_dispatcher_impl.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/compiler_specific.h" | |
11 #include "base/message_loop.h" | |
12 #include "base/time.h" | |
13 #include "media/audio/audio_io.h" | |
14 #include "media/audio/audio_output_proxy.h" | |
15 #include "media/audio/audio_util.h" | |
16 | |
17 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl( | |
18 AudioManager* audio_manager, | |
19 const AudioParameters& params, | |
20 base::TimeDelta close_delay) | |
21 : AudioOutputDispatcher(audio_manager, params), | |
22 pause_delay_(base::TimeDelta::FromMilliseconds( | |
23 2 * params.frames_per_buffer() * | |
24 base::Time::kMillisecondsPerSecond / params.sample_rate())), | |
25 paused_proxies_(0), | |
26 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)), | |
27 close_timer_(FROM_HERE, | |
28 close_delay, | |
29 weak_this_.GetWeakPtr(), | |
30 &AudioOutputDispatcherImpl::ClosePendingStreams) { | |
31 } | |
32 | |
33 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() { | |
34 } | |
35 | |
36 bool AudioOutputDispatcherImpl::StreamOpened() { | |
37 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
38 | |
39 paused_proxies_++; | |
40 | |
41 // Ensure that there is at least one open stream. | |
42 if (idle_streams_.empty() && !CreateAndOpenStream()) { | |
tommi (sloooow) - chröme
2012/04/03 13:47:51
nit: no {}
enal1
2012/04/04 18:46:55
Done.
| |
43 return false; | |
44 } | |
45 | |
46 close_timer_.Reset(); | |
47 return true; | |
48 } | |
49 | |
50 AudioOutputStream* AudioOutputDispatcherImpl::StreamStarted( | |
51 AudioOutputStream::AudioSourceCallback* callback, | |
52 AudioOutputProxy* stream_proxy) { | |
53 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
54 | |
55 if (idle_streams_.empty() && !CreateAndOpenStream()) { | |
tommi (sloooow) - chröme
2012/04/03 13:47:51
nit: no {}
enal1
2012/04/04 18:46:55
Done.
| |
56 return NULL; | |
57 } | |
58 | |
59 AudioOutputStream* stream = idle_streams_.back(); | |
60 idle_streams_.pop_back(); | |
61 | |
62 DCHECK_GT(paused_proxies_, 0u); | |
63 paused_proxies_--; | |
64 | |
65 close_timer_.Reset(); | |
66 | |
67 // Schedule task to allocate streams for other proxies if we need to. | |
68 message_loop_->PostTask(FROM_HERE, base::Bind( | |
69 &AudioOutputDispatcherImpl::OpenTask, weak_this_.GetWeakPtr())); | |
70 | |
71 double volume = 0; | |
72 stream_proxy->GetVolume(&volume); | |
73 stream->SetVolume(volume); | |
74 stream->Start(callback); | |
75 return stream; | |
76 } | |
77 | |
78 void AudioOutputDispatcherImpl::StreamStopped( | |
79 AudioOutputStream* physical_stream, | |
80 AudioOutputProxy* stream_proxy) { | |
81 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
82 | |
83 physical_stream->Stop(); | |
84 | |
85 paused_proxies_++; | |
tommi (sloooow) - chröme
2012/04/03 13:47:51
nit: ++paused_proxies_;
enal1
2012/04/04 18:46:55
Done.
| |
86 | |
87 pausing_streams_.push_front(physical_stream); | |
88 | |
89 // Don't recycle stream until two buffers worth of time has elapsed. | |
90 message_loop_->PostDelayedTask( | |
91 FROM_HERE, | |
92 base::Bind(&AudioOutputDispatcherImpl::StopStreamTask, | |
93 weak_this_.GetWeakPtr()), | |
94 pause_delay_); | |
95 } | |
96 | |
97 void AudioOutputDispatcherImpl::StreamVolumeSet( | |
98 AudioOutputStream* physical_stream, | |
99 double volume) { | |
100 if (physical_stream) | |
tommi (sloooow) - chröme
2012/04/03 13:47:51
missing DCHECK_EQ(MessageLoop::current(), message_
enal1
2012/04/04 18:46:55
Done.
| |
101 physical_stream->SetVolume(volume); | |
102 } | |
103 | |
104 void AudioOutputDispatcherImpl::StopStreamTask() { | |
105 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
106 | |
107 if (pausing_streams_.empty()) | |
108 return; | |
109 | |
110 AudioOutputStream* stream = pausing_streams_.back(); | |
111 pausing_streams_.pop_back(); | |
112 idle_streams_.push_back(stream); | |
113 close_timer_.Reset(); | |
114 } | |
115 | |
116 void AudioOutputDispatcherImpl::StreamClosed(AudioOutputProxy* stream_proxy) { | |
117 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
118 | |
119 while (!pausing_streams_.empty()) { | |
120 idle_streams_.push_back(pausing_streams_.back()); | |
121 pausing_streams_.pop_back(); | |
122 } | |
123 | |
124 DCHECK_GT(paused_proxies_, 0u); | |
125 paused_proxies_--; | |
126 | |
127 while (idle_streams_.size() > paused_proxies_) { | |
128 idle_streams_.back()->Close(); | |
129 idle_streams_.pop_back(); | |
130 } | |
131 } | |
132 | |
133 void AudioOutputDispatcherImpl::Shutdown() { | |
134 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
135 | |
136 // Cancel any pending tasks to close paused streams or create new ones. | |
137 weak_this_.InvalidateWeakPtrs(); | |
138 | |
139 // No AudioOutputProxy objects should hold a reference to us when we get | |
140 // to this stage. | |
141 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference"; | |
142 | |
143 AudioOutputStreamList::iterator it = idle_streams_.begin(); | |
144 for (; it != idle_streams_.end(); ++it) | |
145 (*it)->Close(); | |
146 idle_streams_.clear(); | |
147 | |
148 it = pausing_streams_.begin(); | |
149 for (; it != pausing_streams_.end(); ++it) | |
150 (*it)->Close(); | |
151 pausing_streams_.clear(); | |
152 } | |
153 | |
154 bool AudioOutputDispatcherImpl::CreateAndOpenStream() { | |
155 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_); | |
tommi (sloooow) - chröme
2012/04/03 13:47:51
first DCHECK_EQ(MessageLoop::current(), message_lo
enal1
2012/04/04 18:46:55
Done.
| |
156 if (!stream) | |
157 return false; | |
158 | |
159 if (!stream->Open()) { | |
160 stream->Close(); | |
161 return false; | |
162 } | |
163 idle_streams_.push_back(stream); | |
164 return true; | |
165 } | |
166 | |
167 void AudioOutputDispatcherImpl::OpenTask() { | |
168 // Make sure that we have at least one stream allocated if there | |
tommi (sloooow) - chröme
2012/04/03 13:47:51
DCHECK_EQ(MessageLoop::current(), message_loop_);
enal1
2012/04/04 18:46:55
Done.
| |
169 // are paused streams. | |
170 if (paused_proxies_ > 0 && idle_streams_.empty() && | |
171 pausing_streams_.empty()) { | |
172 CreateAndOpenStream(); | |
173 } | |
174 | |
175 close_timer_.Reset(); | |
176 } | |
177 | |
178 // This method is called by |close_timer_|. | |
179 void AudioOutputDispatcherImpl::ClosePendingStreams() { | |
180 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
181 while (!idle_streams_.empty()) { | |
182 idle_streams_.back()->Close(); | |
183 idle_streams_.pop_back(); | |
184 } | |
185 } | |
OLD | NEW |