Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / media / audio / audio_output_dispatcher_impl.cc
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/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"
15
16 namespace media {
17
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) {}
34
35 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
36   DCHECK_EQ(idle_proxies_, 0u);
37   DCHECK(proxy_to_physical_map_.empty());
38   DCHECK(idle_streams_.empty());
39 }
40
41 bool AudioOutputDispatcherImpl::OpenStream() {
42   DCHECK(task_runner_->BelongsToCurrentThread());
43
44   // Ensure that there is at least one open stream.
45   if (idle_streams_.empty() && !CreateAndOpenStream())
46     return false;
47
48   ++idle_proxies_;
49   close_timer_.Reset();
50   return true;
51 }
52
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());
59
60   if (idle_streams_.empty() && !CreateAndOpenStream())
61     return false;
62
63   AudioOutputStream* physical_stream = idle_streams_.back();
64   idle_streams_.pop_back();
65
66   DCHECK_GT(idle_proxies_, 0u);
67   --idle_proxies_;
68
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;
77
78   close_timer_.Reset();
79   return true;
80 }
81
82 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
83   DCHECK(task_runner_->BelongsToCurrentThread());
84
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);
89
90   physical_stream->Stop();
91   audio_log_->OnStopped(audio_stream_ids_[physical_stream]);
92   ++idle_proxies_;
93   idle_streams_.push_back(physical_stream);
94
95   close_timer_.Reset();
96 }
97
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);
106   }
107 }
108
109 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
110   DCHECK(task_runner_->BelongsToCurrentThread());
111
112   DCHECK_GT(idle_proxies_, 0u);
113   --idle_proxies_;
114
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();
119 }
120
121 void AudioOutputDispatcherImpl::Shutdown() {
122   DCHECK(task_runner_->BelongsToCurrentThread());
123
124   // Close all idle streams immediately.  The |close_timer_| will handle
125   // invalidating any outstanding tasks upon its destruction.
126   CloseAllIdleStreams();
127 }
128
129 bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
130   DCHECK(task_runner_->BelongsToCurrentThread());
131   AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(
132       params_, device_id_);
133   if (!stream)
134     return false;
135
136   if (!stream->Open()) {
137     stream->Close();
138     return false;
139   }
140
141   const int stream_id = audio_stream_id_++;
142   audio_stream_ids_[stream] = stream_id;
143   audio_log_->OnCreated(
144       stream_id, params_, device_id_);
145
146   idle_streams_.push_back(stream);
147   return true;
148 }
149
150 void AudioOutputDispatcherImpl::CloseAllIdleStreams() {
151   DCHECK(task_runner_->BelongsToCurrentThread());
152   CloseIdleStreams(0);
153 }
154
155 void AudioOutputDispatcherImpl::CloseIdleStreams(size_t keep_alive) {
156   DCHECK(task_runner_->BelongsToCurrentThread());
157   if (idle_streams_.size() <= keep_alive)
158     return;
159   for (size_t i = keep_alive; i < idle_streams_.size(); ++i) {
160     AudioOutputStream* stream = idle_streams_[i];
161     stream->Close();
162
163     AudioStreamIDMap::iterator it = audio_stream_ids_.find(stream);
164     DCHECK(it != audio_stream_ids_.end());
165     audio_log_->OnClosed(it->second);
166     audio_stream_ids_.erase(it);
167   }
168   idle_streams_.erase(idle_streams_.begin() + keep_alive, idle_streams_.end());
169 }
170
171 void AudioOutputDispatcherImpl::CloseStreamsForWedgeFix() {
172   DCHECK(task_runner_->BelongsToCurrentThread());
173   CloseAllIdleStreams();
174 }
175
176 void AudioOutputDispatcherImpl::RestartStreamsForWedgeFix() {
177   DCHECK(task_runner_->BelongsToCurrentThread());
178
179   // Should only be called when the dispatcher is used with fake streams which
180   // don't need to be shutdown or restarted.
181   CHECK_EQ(params_.format(), AudioParameters::AUDIO_FAKE);
182 }
183
184 }  // namespace media