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 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
& p
= wav_audio_
.params();
55 const AudioParameters
params(AudioParameters::AUDIO_PCM_LOW_LATENCY
,
60 stream_
= AudioManager::Get()->MakeAudioOutputStreamProxy(params
,
62 if (!stream_
|| !stream_
->Open()) {
63 LOG(ERROR
) << "Failed to open an output stream.";
66 stream_
->SetVolume(kOutputVolumePercent
);
70 base::AutoLock
al(state_lock_
);
72 delayed_stop_posted_
= false;
73 stop_closure_
.Reset(base::Bind(&AudioStreamContainer::StopStream
,
74 base::Unretained(this)));
77 if (wav_audio_
.AtEnd(cursor_
))
86 if (g_audio_source_for_testing
)
87 stream_
->Start(g_audio_source_for_testing
);
91 if (g_observer_for_testing
)
92 g_observer_for_testing
->OnPlay();
96 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
101 stop_closure_
.Cancel();
105 // AudioOutputStream::AudioSourceCallback overrides:
106 // Following methods could be called from *ANY* thread.
107 int OnMoreData(AudioBus
* dest
, uint32
/* total_bytes_delay */) override
{
108 base::AutoLock
al(state_lock_
);
109 size_t bytes_written
= 0;
111 if (wav_audio_
.AtEnd(cursor_
) ||
112 !wav_audio_
.CopyTo(dest
, cursor_
, &bytes_written
)) {
113 if (delayed_stop_posted_
)
115 delayed_stop_posted_
= true;
116 AudioManager::Get()->GetTaskRunner()->PostDelayedTask(
118 stop_closure_
.callback(),
119 base::TimeDelta::FromMilliseconds(kKeepAliveMs
));
122 cursor_
+= bytes_written
;
123 return dest
->frames();
126 void OnError(AudioOutputStream
* /* stream */) override
{
127 LOG(ERROR
) << "Error during system sound reproduction.";
131 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
133 if (stream_
&& started_
) {
134 // Do not hold the |state_lock_| while stopping the output stream.
136 if (g_observer_for_testing
)
137 g_observer_for_testing
->OnStop(cursor_
);
143 // Must only be accessed on the AudioManager::GetTaskRunner() thread.
145 AudioOutputStream
* stream_
;
147 // All variables below must be accessed under |state_lock_| when |started_|.
148 base::Lock state_lock_
;
150 bool delayed_stop_posted_
;
151 const WavAudioHandler wav_audio_
;
152 base::CancelableClosure stop_closure_
;
154 DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer
);
157 AudioStreamHandler::AudioStreamHandler(const base::StringPiece
& wav_data
)
158 : wav_audio_(wav_data
),
159 initialized_(false) {
160 AudioManager
* manager
= AudioManager::Get();
162 LOG(ERROR
) << "Can't get access to audio manager.";
165 if (!wav_audio_
.params().IsValid()) {
166 LOG(ERROR
) << "Audio params are invalid.";
169 stream_
.reset(new AudioStreamContainer(wav_audio_
));
173 AudioStreamHandler::~AudioStreamHandler() {
174 DCHECK(CalledOnValidThread());
175 AudioManager::Get()->GetTaskRunner()->PostTask(
177 base::Bind(&AudioStreamContainer::Stop
, base::Unretained(stream_
.get())));
178 AudioManager::Get()->GetTaskRunner()->DeleteSoon(FROM_HERE
,
182 bool AudioStreamHandler::IsInitialized() const {
183 DCHECK(CalledOnValidThread());
187 bool AudioStreamHandler::Play() {
188 DCHECK(CalledOnValidThread());
190 if (!IsInitialized())
193 AudioManager::Get()->GetTaskRunner()->PostTask(
195 base::Bind(base::IgnoreResult(&AudioStreamContainer::Play
),
196 base::Unretained(stream_
.get())));
200 void AudioStreamHandler::Stop() {
201 DCHECK(CalledOnValidThread());
202 AudioManager::Get()->GetTaskRunner()->PostTask(
204 base::Bind(&AudioStreamContainer::Stop
, base::Unretained(stream_
.get())));
208 void AudioStreamHandler::SetObserverForTesting(TestObserver
* observer
) {
209 g_observer_for_testing
= observer
;
213 void AudioStreamHandler::SetAudioSourceForTesting(
214 AudioOutputStream::AudioSourceCallback
* source
) {
215 g_audio_source_for_testing
= source
;