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"
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"
18 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
19 AudioManager
* audio_manager
,
20 const AudioParameters
& params
,
21 const std::string
& output_device_id
,
22 const std::string
& input_device_id
,
23 const base::TimeDelta
& close_delay
)
24 : AudioOutputDispatcher(audio_manager
,
29 close_timer_(FROM_HERE
,
32 &AudioOutputDispatcherImpl::CloseAllIdleStreams
),
34 audio_manager
->CreateAudioLog(AudioLogFactory::AUDIO_OUTPUT_STREAM
)),
35 audio_stream_id_(0) {}
37 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
38 DCHECK_EQ(idle_proxies_
, 0u);
39 DCHECK(proxy_to_physical_map_
.empty());
40 DCHECK(idle_streams_
.empty());
43 bool AudioOutputDispatcherImpl::OpenStream() {
44 DCHECK(task_runner_
->BelongsToCurrentThread());
46 // Ensure that there is at least one open stream.
47 if (idle_streams_
.empty() && !CreateAndOpenStream())
55 bool AudioOutputDispatcherImpl::StartStream(
56 AudioOutputStream::AudioSourceCallback
* callback
,
57 AudioOutputProxy
* stream_proxy
) {
58 DCHECK(task_runner_
->BelongsToCurrentThread());
59 DCHECK(proxy_to_physical_map_
.find(stream_proxy
) ==
60 proxy_to_physical_map_
.end());
62 if (idle_streams_
.empty() && !CreateAndOpenStream())
65 AudioOutputStream
* physical_stream
= idle_streams_
.back();
66 idle_streams_
.pop_back();
68 DCHECK_GT(idle_proxies_
, 0u);
72 stream_proxy
->GetVolume(&volume
);
73 physical_stream
->SetVolume(volume
);
74 const int stream_id
= audio_stream_ids_
[physical_stream
];
75 audio_log_
->OnSetVolume(stream_id
, volume
);
76 physical_stream
->Start(callback
);
77 audio_log_
->OnStarted(stream_id
);
78 proxy_to_physical_map_
[stream_proxy
] = physical_stream
;
84 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy
* stream_proxy
) {
85 DCHECK(task_runner_
->BelongsToCurrentThread());
87 AudioStreamMap::iterator it
= proxy_to_physical_map_
.find(stream_proxy
);
88 DCHECK(it
!= proxy_to_physical_map_
.end());
89 AudioOutputStream
* physical_stream
= it
->second
;
90 proxy_to_physical_map_
.erase(it
);
92 physical_stream
->Stop();
93 audio_log_
->OnStopped(audio_stream_ids_
[physical_stream
]);
95 idle_streams_
.push_back(physical_stream
);
100 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy
* stream_proxy
,
102 DCHECK(task_runner_
->BelongsToCurrentThread());
103 AudioStreamMap::iterator it
= proxy_to_physical_map_
.find(stream_proxy
);
104 if (it
!= proxy_to_physical_map_
.end()) {
105 AudioOutputStream
* physical_stream
= it
->second
;
106 physical_stream
->SetVolume(volume
);
107 audio_log_
->OnSetVolume(audio_stream_ids_
[physical_stream
], volume
);
111 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy
* stream_proxy
) {
112 DCHECK(task_runner_
->BelongsToCurrentThread());
114 DCHECK_GT(idle_proxies_
, 0u);
117 // Leave at least a single stream running until the close timer fires to help
118 // cycle time when streams are opened and closed repeatedly.
119 CloseIdleStreams(std::max(idle_proxies_
, static_cast<size_t>(1)));
120 close_timer_
.Reset();
123 void AudioOutputDispatcherImpl::Shutdown() {
124 DCHECK(task_runner_
->BelongsToCurrentThread());
126 // Close all idle streams immediately. The |close_timer_| will handle
127 // invalidating any outstanding tasks upon its destruction.
128 CloseAllIdleStreams();
131 bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
132 DCHECK(task_runner_
->BelongsToCurrentThread());
133 AudioOutputStream
* stream
= audio_manager_
->MakeAudioOutputStream(
134 params_
, output_device_id_
, input_device_id_
);
138 if (!stream
->Open()) {
143 const int stream_id
= audio_stream_id_
++;
144 audio_stream_ids_
[stream
] = stream_id
;
145 audio_log_
->OnCreated(
146 stream_id
, params_
, input_device_id_
, output_device_id_
);
148 idle_streams_
.push_back(stream
);
152 void AudioOutputDispatcherImpl::CloseAllIdleStreams() {
153 DCHECK(task_runner_
->BelongsToCurrentThread());
157 void AudioOutputDispatcherImpl::CloseIdleStreams(size_t keep_alive
) {
158 DCHECK(task_runner_
->BelongsToCurrentThread());
159 if (idle_streams_
.size() <= keep_alive
)
161 for (size_t i
= keep_alive
; i
< idle_streams_
.size(); ++i
) {
162 AudioOutputStream
* stream
= idle_streams_
[i
];
165 AudioStreamIDMap::iterator it
= audio_stream_ids_
.find(stream
);
166 DCHECK(it
!= audio_stream_ids_
.end());
167 audio_log_
->OnClosed(it
->second
);
168 audio_stream_ids_
.erase(it
);
170 idle_streams_
.erase(idle_streams_
.begin() + keep_alive
, idle_streams_
.end());
173 void AudioOutputDispatcherImpl::CloseStreamsForWedgeFix() {
174 DCHECK(task_runner_
->BelongsToCurrentThread());
175 CloseAllIdleStreams();
178 void AudioOutputDispatcherImpl::RestartStreamsForWedgeFix() {
179 DCHECK(task_runner_
->BelongsToCurrentThread());
181 // Should only be called when the dispatcher is used with fake streams which
182 // don't need to be shutdown or restarted.
183 CHECK_EQ(params_
.format(), AudioParameters::AUDIO_FAKE
);