Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / media / audio / audio_output_dispatcher_impl.cc
blob521f91d13342ba8258456660d6135a43847e40ab
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_io.h"
14 #include "media/audio/audio_output_proxy.h"
16 namespace media {
18 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
19 AudioManager* audio_manager,
20 const AudioParameters& params,
21 const std::string& output_device_id,
22 const base::TimeDelta& close_delay)
23 : AudioOutputDispatcher(audio_manager,
24 params,
25 output_device_id),
26 idle_proxies_(0),
27 close_timer_(FROM_HERE,
28 close_delay,
29 this,
30 &AudioOutputDispatcherImpl::CloseAllIdleStreams),
31 audio_log_(
32 audio_manager->CreateAudioLog(AudioLogFactory::AUDIO_OUTPUT_STREAM)),
33 audio_stream_id_(0) {}
35 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
36 DCHECK_EQ(idle_proxies_, 0u);
37 DCHECK(proxy_to_physical_map_.empty());
38 DCHECK(idle_streams_.empty());
41 bool AudioOutputDispatcherImpl::OpenStream() {
42 DCHECK(task_runner_->BelongsToCurrentThread());
44 // Ensure that there is at least one open stream.
45 if (idle_streams_.empty() && !CreateAndOpenStream())
46 return false;
48 ++idle_proxies_;
49 close_timer_.Reset();
50 return true;
53 bool AudioOutputDispatcherImpl::StartStream(
54 AudioOutputStream::AudioSourceCallback* callback,
55 AudioOutputProxy* stream_proxy) {
56 DCHECK(task_runner_->BelongsToCurrentThread());
57 DCHECK(proxy_to_physical_map_.find(stream_proxy) ==
58 proxy_to_physical_map_.end());
60 if (idle_streams_.empty() && !CreateAndOpenStream())
61 return false;
63 AudioOutputStream* physical_stream = idle_streams_.back();
64 idle_streams_.pop_back();
66 DCHECK_GT(idle_proxies_, 0u);
67 --idle_proxies_;
69 double volume = 0;
70 stream_proxy->GetVolume(&volume);
71 physical_stream->SetVolume(volume);
72 const int stream_id = audio_stream_ids_[physical_stream];
73 audio_log_->OnSetVolume(stream_id, volume);
74 physical_stream->Start(callback);
75 audio_log_->OnStarted(stream_id);
76 proxy_to_physical_map_[stream_proxy] = physical_stream;
78 close_timer_.Reset();
79 return true;
82 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
83 DCHECK(task_runner_->BelongsToCurrentThread());
85 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
86 DCHECK(it != proxy_to_physical_map_.end());
87 AudioOutputStream* physical_stream = it->second;
88 proxy_to_physical_map_.erase(it);
90 physical_stream->Stop();
91 audio_log_->OnStopped(audio_stream_ids_[physical_stream]);
92 ++idle_proxies_;
93 idle_streams_.push_back(physical_stream);
95 close_timer_.Reset();
98 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
99 double volume) {
100 DCHECK(task_runner_->BelongsToCurrentThread());
101 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
102 if (it != proxy_to_physical_map_.end()) {
103 AudioOutputStream* physical_stream = it->second;
104 physical_stream->SetVolume(volume);
105 audio_log_->OnSetVolume(audio_stream_ids_[physical_stream], volume);
109 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
110 DCHECK(task_runner_->BelongsToCurrentThread());
112 DCHECK_GT(idle_proxies_, 0u);
113 --idle_proxies_;
115 // Leave at least a single stream running until the close timer fires to help
116 // cycle time when streams are opened and closed repeatedly.
117 CloseIdleStreams(std::max(idle_proxies_, static_cast<size_t>(1)));
118 close_timer_.Reset();
121 void AudioOutputDispatcherImpl::Shutdown() {
122 DCHECK(task_runner_->BelongsToCurrentThread());
124 // Close all idle streams immediately. The |close_timer_| will handle
125 // invalidating any outstanding tasks upon its destruction.
126 CloseAllIdleStreams();
128 // No AudioOutputProxy objects should hold a reference to us when we get
129 // to this stage.
130 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
133 bool AudioOutputDispatcherImpl::HasOutputProxies() const {
134 return idle_proxies_ || !proxy_to_physical_map_.empty();
137 bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
138 DCHECK(task_runner_->BelongsToCurrentThread());
139 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(
140 params_, device_id_);
141 if (!stream)
142 return false;
144 if (!stream->Open()) {
145 stream->Close();
146 return false;
149 const int stream_id = audio_stream_id_++;
150 audio_stream_ids_[stream] = stream_id;
151 audio_log_->OnCreated(
152 stream_id, params_, device_id_);
154 idle_streams_.push_back(stream);
155 return true;
158 void AudioOutputDispatcherImpl::CloseAllIdleStreams() {
159 DCHECK(task_runner_->BelongsToCurrentThread());
160 CloseIdleStreams(0);
163 void AudioOutputDispatcherImpl::CloseIdleStreams(size_t keep_alive) {
164 DCHECK(task_runner_->BelongsToCurrentThread());
165 if (idle_streams_.size() <= keep_alive)
166 return;
167 for (size_t i = keep_alive; i < idle_streams_.size(); ++i) {
168 AudioOutputStream* stream = idle_streams_[i];
169 stream->Close();
171 AudioStreamIDMap::iterator it = audio_stream_ids_.find(stream);
172 DCHECK(it != audio_stream_ids_.end());
173 audio_log_->OnClosed(it->second);
174 audio_stream_ids_.erase(it);
176 idle_streams_.erase(idle_streams_.begin() + keep_alive, idle_streams_.end());
179 } // namespace media