Create an initial chrome://supervised-user-internals page
[chromium-blink-merge.git] / media / audio / audio_output_dispatcher_impl.cc
bloba2d9fc214dd4777ba8b97262f44660f49ae99547
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.
5 #include "media/audio/audio_output_dispatcher_impl.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/compiler_specific.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/time/time.h"
13 #include "media/audio/audio_output_proxy.h"
15 namespace media {
17 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
18 AudioManager* audio_manager,
19 const AudioParameters& params,
20 const std::string& output_device_id,
21 const base::TimeDelta& close_delay)
22 : AudioOutputDispatcher(audio_manager,
23 params,
24 output_device_id),
25 idle_proxies_(0),
26 close_timer_(FROM_HERE,
27 close_delay,
28 this,
29 &AudioOutputDispatcherImpl::CloseAllIdleStreams),
30 audio_log_(
31 audio_manager->CreateAudioLog(AudioLogFactory::AUDIO_OUTPUT_STREAM)),
32 audio_stream_id_(0) {}
34 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
35 DCHECK_EQ(idle_proxies_, 0u);
36 DCHECK(proxy_to_physical_map_.empty());
37 DCHECK(idle_streams_.empty());
40 bool AudioOutputDispatcherImpl::OpenStream() {
41 DCHECK(task_runner_->BelongsToCurrentThread());
43 // Ensure that there is at least one open stream.
44 if (idle_streams_.empty() && !CreateAndOpenStream())
45 return false;
47 ++idle_proxies_;
48 close_timer_.Reset();
49 return true;
52 bool AudioOutputDispatcherImpl::StartStream(
53 AudioOutputStream::AudioSourceCallback* callback,
54 AudioOutputProxy* stream_proxy) {
55 DCHECK(task_runner_->BelongsToCurrentThread());
56 DCHECK(proxy_to_physical_map_.find(stream_proxy) ==
57 proxy_to_physical_map_.end());
59 if (idle_streams_.empty() && !CreateAndOpenStream())
60 return false;
62 AudioOutputStream* physical_stream = idle_streams_.back();
63 idle_streams_.pop_back();
65 DCHECK_GT(idle_proxies_, 0u);
66 --idle_proxies_;
68 double volume = 0;
69 stream_proxy->GetVolume(&volume);
70 physical_stream->SetVolume(volume);
71 const int stream_id = audio_stream_ids_[physical_stream];
72 audio_log_->OnSetVolume(stream_id, volume);
73 physical_stream->Start(callback);
74 audio_log_->OnStarted(stream_id);
75 proxy_to_physical_map_[stream_proxy] = physical_stream;
77 close_timer_.Reset();
78 return true;
81 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
82 DCHECK(task_runner_->BelongsToCurrentThread());
84 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
85 DCHECK(it != proxy_to_physical_map_.end());
86 AudioOutputStream* physical_stream = it->second;
87 proxy_to_physical_map_.erase(it);
89 physical_stream->Stop();
90 audio_log_->OnStopped(audio_stream_ids_[physical_stream]);
91 ++idle_proxies_;
92 idle_streams_.push_back(physical_stream);
94 close_timer_.Reset();
97 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
98 double volume) {
99 DCHECK(task_runner_->BelongsToCurrentThread());
100 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
101 if (it != proxy_to_physical_map_.end()) {
102 AudioOutputStream* physical_stream = it->second;
103 physical_stream->SetVolume(volume);
104 audio_log_->OnSetVolume(audio_stream_ids_[physical_stream], volume);
108 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
109 DCHECK(task_runner_->BelongsToCurrentThread());
111 DCHECK_GT(idle_proxies_, 0u);
112 --idle_proxies_;
114 // Leave at least a single stream running until the close timer fires to help
115 // cycle time when streams are opened and closed repeatedly.
116 CloseIdleStreams(std::max(idle_proxies_, static_cast<size_t>(1)));
117 close_timer_.Reset();
120 void AudioOutputDispatcherImpl::Shutdown() {
121 DCHECK(task_runner_->BelongsToCurrentThread());
123 // Close all idle streams immediately. The |close_timer_| will handle
124 // invalidating any outstanding tasks upon its destruction.
125 CloseAllIdleStreams();
127 // No AudioOutputProxy objects should hold a reference to us when we get
128 // to this stage.
129 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
132 bool AudioOutputDispatcherImpl::HasOutputProxies() const {
133 return idle_proxies_ || !proxy_to_physical_map_.empty();
136 bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
137 DCHECK(task_runner_->BelongsToCurrentThread());
138 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(
139 params_, device_id_);
140 if (!stream)
141 return false;
143 if (!stream->Open()) {
144 stream->Close();
145 return false;
148 const int stream_id = audio_stream_id_++;
149 audio_stream_ids_[stream] = stream_id;
150 audio_log_->OnCreated(
151 stream_id, params_, device_id_);
153 idle_streams_.push_back(stream);
154 return true;
157 void AudioOutputDispatcherImpl::CloseAllIdleStreams() {
158 DCHECK(task_runner_->BelongsToCurrentThread());
159 CloseIdleStreams(0);
162 void AudioOutputDispatcherImpl::CloseIdleStreams(size_t keep_alive) {
163 DCHECK(task_runner_->BelongsToCurrentThread());
164 if (idle_streams_.size() <= keep_alive)
165 return;
166 for (size_t i = keep_alive; i < idle_streams_.size(); ++i) {
167 AudioOutputStream* stream = idle_streams_[i];
168 stream->Close();
170 AudioStreamIDMap::iterator it = audio_stream_ids_.find(stream);
171 DCHECK(it != audio_stream_ids_.end());
172 audio_log_->OnClosed(it->second);
173 audio_stream_ids_.erase(it);
175 idle_streams_.erase(idle_streams_.begin() + keep_alive, idle_streams_.end());
178 } // namespace media