1 // Copyright 2013 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/sounds/audio_stream_handler.h"
9 #include "base/cancelable_callback.h"
10 #include "base/logging.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/synchronization/lock.h"
13 #include "base/time/time.h"
14 #include "media/audio/audio_manager.h"
15 #include "media/audio/audio_manager_base.h"
16 #include "media/base/channel_layout.h"
23 const double kOutputVolumePercent
= 0.8;
25 // The number of frames each OnMoreData() call will request.
26 const int kDefaultFrameCount
= 1024;
28 // Keep alive timeout for audio stream.
29 const int kKeepAliveMs
= 1500;
31 AudioStreamHandler::TestObserver
* g_observer_for_testing
= NULL
;
32 AudioOutputStream::AudioSourceCallback
* g_audio_source_for_testing
= NULL
;
36 class AudioStreamHandler::AudioStreamContainer
37 : public AudioOutputStream::AudioSourceCallback
{
39 explicit AudioStreamContainer(const WavAudioHandler
& wav_audio
)
43 delayed_stop_posted_(false),
44 wav_audio_(wav_audio
) {}
46 ~AudioStreamContainer() override
{
47 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
51 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
54 const AudioParameters
params(
55 AudioParameters::AUDIO_PCM_LOW_LATENCY
,
56 GuessChannelLayout(wav_audio_
.num_channels()),
57 wav_audio_
.sample_rate(), wav_audio_
.bits_per_sample(),
59 stream_
= AudioManager::Get()->MakeAudioOutputStreamProxy(params
,
61 if (!stream_
|| !stream_
->Open()) {
62 LOG(ERROR
) << "Failed to open an output stream.";
65 stream_
->SetVolume(kOutputVolumePercent
);
69 base::AutoLock
al(state_lock_
);
71 delayed_stop_posted_
= false;
72 stop_closure_
.Reset(base::Bind(&AudioStreamContainer::StopStream
,
73 base::Unretained(this)));
76 if (wav_audio_
.AtEnd(cursor_
))
85 if (g_audio_source_for_testing
)
86 stream_
->Start(g_audio_source_for_testing
);
90 if (g_observer_for_testing
)
91 g_observer_for_testing
->OnPlay();
95 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
100 stop_closure_
.Cancel();
104 // AudioOutputStream::AudioSourceCallback overrides:
105 // Following methods could be called from *ANY* thread.
106 int OnMoreData(AudioBus
* dest
, uint32
/* total_bytes_delay */) override
{
107 base::AutoLock
al(state_lock_
);
108 size_t bytes_written
= 0;
110 if (wav_audio_
.AtEnd(cursor_
) ||
111 !wav_audio_
.CopyTo(dest
, cursor_
, &bytes_written
)) {
112 if (delayed_stop_posted_
)
114 delayed_stop_posted_
= true;
115 AudioManager::Get()->GetTaskRunner()->PostDelayedTask(
117 stop_closure_
.callback(),
118 base::TimeDelta::FromMilliseconds(kKeepAliveMs
));
121 cursor_
+= bytes_written
;
122 return dest
->frames();
125 void OnError(AudioOutputStream
* /* stream */) override
{
126 LOG(ERROR
) << "Error during system sound reproduction.";
130 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
132 if (stream_
&& started_
) {
133 // Do not hold the |state_lock_| while stopping the output stream.
135 if (g_observer_for_testing
)
136 g_observer_for_testing
->OnStop(cursor_
);
142 // Must only be accessed on the AudioManager::GetTaskRunner() thread.
144 AudioOutputStream
* stream_
;
146 // All variables below must be accessed under |state_lock_| when |started_|.
147 base::Lock state_lock_
;
149 bool delayed_stop_posted_
;
150 const WavAudioHandler wav_audio_
;
151 base::CancelableClosure stop_closure_
;
153 DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer
);
156 AudioStreamHandler::AudioStreamHandler(const base::StringPiece
& wav_data
)
157 : wav_audio_(wav_data
),
158 initialized_(false) {
159 AudioManager
* manager
= AudioManager::Get();
161 LOG(ERROR
) << "Can't get access to audio manager.";
164 const AudioParameters
params(
165 AudioParameters::AUDIO_PCM_LOW_LATENCY
,
166 GuessChannelLayout(wav_audio_
.num_channels()), wav_audio_
.sample_rate(),
167 wav_audio_
.bits_per_sample(), kDefaultFrameCount
);
168 if (!params
.IsValid()) {
169 LOG(ERROR
) << "Audio params are invalid.";
172 stream_
.reset(new AudioStreamContainer(wav_audio_
));
176 AudioStreamHandler::~AudioStreamHandler() {
177 DCHECK(CalledOnValidThread());
178 AudioManager::Get()->GetTaskRunner()->PostTask(
180 base::Bind(&AudioStreamContainer::Stop
, base::Unretained(stream_
.get())));
181 AudioManager::Get()->GetTaskRunner()->DeleteSoon(FROM_HERE
,
185 bool AudioStreamHandler::IsInitialized() const {
186 DCHECK(CalledOnValidThread());
190 bool AudioStreamHandler::Play() {
191 DCHECK(CalledOnValidThread());
193 if (!IsInitialized())
196 AudioManager::Get()->GetTaskRunner()->PostTask(
198 base::Bind(base::IgnoreResult(&AudioStreamContainer::Play
),
199 base::Unretained(stream_
.get())));
203 void AudioStreamHandler::Stop() {
204 DCHECK(CalledOnValidThread());
205 AudioManager::Get()->GetTaskRunner()->PostTask(
207 base::Bind(&AudioStreamContainer::Stop
, base::Unretained(stream_
.get())));
211 void AudioStreamHandler::SetObserverForTesting(TestObserver
* observer
) {
212 g_observer_for_testing
= observer
;
216 void AudioStreamHandler::SetAudioSourceForTesting(
217 AudioOutputStream::AudioSourceCallback
* source
) {
218 g_audio_source_for_testing
= source
;