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

Side by Side Diff: trunk/src/media/audio/audio_output_dispatcher_impl.cc

Issue 38533002: Revert 230334 "Improve and simplify AudioOutputDispatcher." (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: Created 7 years, 1 month 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
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/audio_output_dispatcher_impl.h" 5 #include "media/audio/audio_output_dispatcher_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/message_loop/message_loop.h" 11 #include "base/message_loop/message_loop.h"
12 #include "base/time/time.h" 12 #include "base/time/time.h"
13 #include "media/audio/audio_io.h" 13 #include "media/audio/audio_io.h"
14 #include "media/audio/audio_output_proxy.h" 14 #include "media/audio/audio_output_proxy.h"
15 15
16 namespace media { 16 namespace media {
17 17
18 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl( 18 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
19 AudioManager* audio_manager, 19 AudioManager* audio_manager,
20 const AudioParameters& params, 20 const AudioParameters& params,
21 const std::string& output_device_id, 21 const std::string& output_device_id,
22 const std::string& input_device_id, 22 const std::string& input_device_id,
23 const base::TimeDelta& close_delay) 23 const base::TimeDelta& close_delay)
24 : AudioOutputDispatcher(audio_manager, 24 : AudioOutputDispatcher(audio_manager, params, output_device_id,
25 params, 25 input_device_id),
26 output_device_id, 26 pause_delay_(base::TimeDelta::FromMicroseconds(
27 input_device_id), 27 2 * params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
28 idle_proxies_(0), 28 static_cast<float>(params.sample_rate()))),
29 paused_proxies_(0),
30 weak_this_(this),
29 close_timer_(FROM_HERE, 31 close_timer_(FROM_HERE,
30 close_delay, 32 close_delay,
31 this, 33 this,
32 &AudioOutputDispatcherImpl::CloseIdleStreams) {} 34 &AudioOutputDispatcherImpl::ClosePendingStreams) {
35 }
33 36
34 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() { 37 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
35 DCHECK_EQ(idle_proxies_, 0u);
36 DCHECK(proxy_to_physical_map_.empty()); 38 DCHECK(proxy_to_physical_map_.empty());
37 DCHECK(idle_streams_.empty()); 39 DCHECK(idle_streams_.empty());
40 DCHECK(pausing_streams_.empty());
38 } 41 }
39 42
40 bool AudioOutputDispatcherImpl::OpenStream() { 43 bool AudioOutputDispatcherImpl::OpenStream() {
41 DCHECK(message_loop_->BelongsToCurrentThread()); 44 DCHECK(message_loop_->BelongsToCurrentThread());
42 45
46 paused_proxies_++;
47
43 // Ensure that there is at least one open stream. 48 // Ensure that there is at least one open stream.
44 if (idle_streams_.empty() && !CreateAndOpenStream()) 49 if (idle_streams_.empty() && !CreateAndOpenStream()) {
50 paused_proxies_--;
45 return false; 51 return false;
52 }
46 53
47 ++idle_proxies_;
48 close_timer_.Reset(); 54 close_timer_.Reset();
49 return true; 55 return true;
50 } 56 }
51 57
52 bool AudioOutputDispatcherImpl::StartStream( 58 bool AudioOutputDispatcherImpl::StartStream(
53 AudioOutputStream::AudioSourceCallback* callback, 59 AudioOutputStream::AudioSourceCallback* callback,
54 AudioOutputProxy* stream_proxy) { 60 AudioOutputProxy* stream_proxy) {
55 DCHECK(message_loop_->BelongsToCurrentThread()); 61 DCHECK(message_loop_->BelongsToCurrentThread());
56 62
57 if (idle_streams_.empty() && !CreateAndOpenStream()) 63 if (idle_streams_.empty() && !CreateAndOpenStream())
58 return false; 64 return false;
59 65
60 AudioOutputStream* physical_stream = idle_streams_.back(); 66 AudioOutputStream* physical_stream = idle_streams_.back();
67 DCHECK(physical_stream);
61 idle_streams_.pop_back(); 68 idle_streams_.pop_back();
62 69
63 DCHECK_GT(idle_proxies_, 0u); 70 DCHECK_GT(paused_proxies_, 0u);
64 --idle_proxies_; 71 --paused_proxies_;
72
73 close_timer_.Reset();
74
75 // Schedule task to allocate streams for other proxies if we need to.
76 message_loop_->PostTask(FROM_HERE, base::Bind(
77 &AudioOutputDispatcherImpl::OpenTask, weak_this_.GetWeakPtr()));
65 78
66 double volume = 0; 79 double volume = 0;
67 stream_proxy->GetVolume(&volume); 80 stream_proxy->GetVolume(&volume);
68 physical_stream->SetVolume(volume); 81 physical_stream->SetVolume(volume);
69 physical_stream->Start(callback); 82 physical_stream->Start(callback);
70 proxy_to_physical_map_[stream_proxy] = physical_stream; 83 proxy_to_physical_map_[stream_proxy] = physical_stream;
71
72 close_timer_.Reset();
73 return true; 84 return true;
74 } 85 }
75 86
76 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) { 87 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
77 DCHECK(message_loop_->BelongsToCurrentThread()); 88 DCHECK(message_loop_->BelongsToCurrentThread());
78 89
79 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); 90 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
80 DCHECK(it != proxy_to_physical_map_.end()); 91 DCHECK(it != proxy_to_physical_map_.end());
81 AudioOutputStream* physical_stream = it->second; 92 AudioOutputStream* physical_stream = it->second;
82 proxy_to_physical_map_.erase(it); 93 proxy_to_physical_map_.erase(it);
83 94
84 physical_stream->Stop(); 95 physical_stream->Stop();
85 ++idle_proxies_;
86 idle_streams_.push_back(physical_stream);
87 96
88 close_timer_.Reset(); 97 ++paused_proxies_;
98
99 pausing_streams_.push_front(physical_stream);
100
101 // Don't recycle stream until two buffers worth of time has elapsed.
102 message_loop_->PostDelayedTask(
103 FROM_HERE,
104 base::Bind(&AudioOutputDispatcherImpl::StopStreamTask,
105 weak_this_.GetWeakPtr()),
106 pause_delay_);
89 } 107 }
90 108
91 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy, 109 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
92 double volume) { 110 double volume) {
93 DCHECK(message_loop_->BelongsToCurrentThread()); 111 DCHECK(message_loop_->BelongsToCurrentThread());
94 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy); 112 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
95 if (it != proxy_to_physical_map_.end()) { 113 if (it != proxy_to_physical_map_.end()) {
96 AudioOutputStream* physical_stream = it->second; 114 AudioOutputStream* physical_stream = it->second;
97 physical_stream->SetVolume(volume); 115 physical_stream->SetVolume(volume);
98 } 116 }
99 } 117 }
100 118
119 void AudioOutputDispatcherImpl::StopStreamTask() {
120 DCHECK(message_loop_->BelongsToCurrentThread());
121
122 if (pausing_streams_.empty())
123 return;
124
125 AudioOutputStream* stream = pausing_streams_.back();
126 pausing_streams_.pop_back();
127 idle_streams_.push_back(stream);
128 close_timer_.Reset();
129 }
130
101 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) { 131 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
102 DCHECK(message_loop_->BelongsToCurrentThread()); 132 DCHECK(message_loop_->BelongsToCurrentThread());
103 133
104 DCHECK_GT(idle_proxies_, 0u); 134 while (!pausing_streams_.empty()) {
105 --idle_proxies_; 135 idle_streams_.push_back(pausing_streams_.back());
136 pausing_streams_.pop_back();
137 }
106 138
107 // Leave a single stream running until the close timer fires to help cycle 139 DCHECK_GT(paused_proxies_, 0u);
108 // time when streams are opened and closed repeatedly. 140 paused_proxies_--;
109 static const size_t kStreamKeepAliveCount = 1; 141
110 if (idle_streams_.size() > kStreamKeepAliveCount) { 142 while (idle_streams_.size() > paused_proxies_) {
111 for (size_t i = kStreamKeepAliveCount; i < idle_streams_.size(); ++i) 143 idle_streams_.back()->Close();
112 idle_streams_[i]->Close(); 144 idle_streams_.pop_back();
113 idle_streams_.erase(idle_streams_.begin() + kStreamKeepAliveCount,
114 idle_streams_.end());
115 } 145 }
116 close_timer_.Reset();
117 } 146 }
118 147
119 void AudioOutputDispatcherImpl::Shutdown() { 148 void AudioOutputDispatcherImpl::Shutdown() {
120 DCHECK(message_loop_->BelongsToCurrentThread()); 149 DCHECK(message_loop_->BelongsToCurrentThread());
121 150
122 // Close all idle streams immediately. The |close_timer_| will handle 151 // Cancel any pending tasks to close paused streams or create new ones.
123 // invalidating any outstanding tasks upon its destruction. 152 weak_this_.InvalidateWeakPtrs();
124 CloseIdleStreams(); 153
154 // No AudioOutputProxy objects should hold a reference to us when we get
155 // to this stage.
156 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
157
158 AudioOutputStreamList::iterator it = idle_streams_.begin();
159 for (; it != idle_streams_.end(); ++it)
160 (*it)->Close();
161 idle_streams_.clear();
162
163 it = pausing_streams_.begin();
164 for (; it != pausing_streams_.end(); ++it)
165 (*it)->Close();
166 pausing_streams_.clear();
125 } 167 }
126 168
127 bool AudioOutputDispatcherImpl::CreateAndOpenStream() { 169 bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
128 DCHECK(message_loop_->BelongsToCurrentThread()); 170 DCHECK(message_loop_->BelongsToCurrentThread());
129 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream( 171 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(
130 params_, output_device_id_, input_device_id_); 172 params_, output_device_id_, input_device_id_);
131 if (!stream) 173 if (!stream)
132 return false; 174 return false;
133 175
134 if (!stream->Open()) { 176 if (!stream->Open()) {
135 stream->Close(); 177 stream->Close();
136 return false; 178 return false;
137 } 179 }
138
139 idle_streams_.push_back(stream); 180 idle_streams_.push_back(stream);
140 return true; 181 return true;
141 } 182 }
142 183
143 void AudioOutputDispatcherImpl::CloseIdleStreams() { 184 void AudioOutputDispatcherImpl::OpenTask() {
144 DCHECK(message_loop_->BelongsToCurrentThread()); 185 DCHECK(message_loop_->BelongsToCurrentThread());
145 for (size_t i = 0; i < idle_streams_.size(); ++i) 186 // Make sure that we have at least one stream allocated if there
146 idle_streams_[i]->Close(); 187 // are paused streams.
147 idle_streams_.clear(); 188 if (paused_proxies_ > 0 && idle_streams_.empty() &&
189 pausing_streams_.empty()) {
190 CreateAndOpenStream();
191 }
192
193 close_timer_.Reset();
194 }
195
196 // This method is called by |close_timer_|.
197 void AudioOutputDispatcherImpl::ClosePendingStreams() {
198 DCHECK(message_loop_->BelongsToCurrentThread());
199 while (!idle_streams_.empty()) {
200 idle_streams_.back()->Close();
201 idle_streams_.pop_back();
202 }
148 } 203 }
149 204
150 } // namespace media 205 } // namespace media
OLDNEW
« no previous file with comments | « trunk/src/media/audio/audio_output_dispatcher_impl.h ('k') | trunk/src/media/audio/audio_output_proxy_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698