Files.app: Remove wait for startup animation.
[chromium-blink-merge.git] / media / audio / sounds / audio_stream_handler.cc
blob28758b237131ad31ea8d95a8eafe69e5bf191969
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"
7 #include <string>
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"
18 namespace media {
20 namespace {
22 // Volume percent.
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;
34 } // namespace
36 class AudioStreamHandler::AudioStreamContainer
37 : public AudioOutputStream::AudioSourceCallback {
38 public:
39 explicit AudioStreamContainer(const WavAudioHandler& wav_audio)
40 : started_(false),
41 stream_(NULL),
42 cursor_(0),
43 delayed_stop_posted_(false),
44 wav_audio_(wav_audio) {}
46 ~AudioStreamContainer() override {
47 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
50 void Play() {
51 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
53 if (!stream_) {
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(),
58 kDefaultFrameCount);
59 stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(params,
60 std::string());
61 if (!stream_ || !stream_->Open()) {
62 LOG(ERROR) << "Failed to open an output stream.";
63 return;
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)));
75 if (started_) {
76 if (wav_audio_.AtEnd(cursor_))
77 cursor_ = 0;
78 return;
81 cursor_ = 0;
84 started_ = true;
85 if (g_audio_source_for_testing)
86 stream_->Start(g_audio_source_for_testing);
87 else
88 stream_->Start(this);
90 if (g_observer_for_testing)
91 g_observer_for_testing->OnPlay();
94 void Stop() {
95 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
96 StopStream();
97 if (stream_)
98 stream_->Close();
99 stream_ = NULL;
100 stop_closure_.Cancel();
103 private:
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_)
113 return 0;
114 delayed_stop_posted_ = true;
115 AudioManager::Get()->GetTaskRunner()->PostDelayedTask(
116 FROM_HERE,
117 stop_closure_.callback(),
118 base::TimeDelta::FromMilliseconds(kKeepAliveMs));
119 return 0;
121 cursor_ += bytes_written;
122 return dest->frames();
125 void OnError(AudioOutputStream* /* stream */) override {
126 LOG(ERROR) << "Error during system sound reproduction.";
129 void StopStream() {
130 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
132 if (stream_ && started_) {
133 // Do not hold the |state_lock_| while stopping the output stream.
134 stream_->Stop();
135 if (g_observer_for_testing)
136 g_observer_for_testing->OnStop(cursor_);
139 started_ = false;
142 // Must only be accessed on the AudioManager::GetTaskRunner() thread.
143 bool started_;
144 AudioOutputStream* stream_;
146 // All variables below must be accessed under |state_lock_| when |started_|.
147 base::Lock state_lock_;
148 size_t cursor_;
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();
160 if (!manager) {
161 LOG(ERROR) << "Can't get access to audio manager.";
162 return;
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.";
170 return;
172 stream_.reset(new AudioStreamContainer(wav_audio_));
173 initialized_ = true;
176 AudioStreamHandler::~AudioStreamHandler() {
177 DCHECK(CalledOnValidThread());
178 AudioManager::Get()->GetTaskRunner()->PostTask(
179 FROM_HERE,
180 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
181 AudioManager::Get()->GetTaskRunner()->DeleteSoon(FROM_HERE,
182 stream_.release());
185 bool AudioStreamHandler::IsInitialized() const {
186 DCHECK(CalledOnValidThread());
187 return initialized_;
190 bool AudioStreamHandler::Play() {
191 DCHECK(CalledOnValidThread());
193 if (!IsInitialized())
194 return false;
196 AudioManager::Get()->GetTaskRunner()->PostTask(
197 FROM_HERE,
198 base::Bind(base::IgnoreResult(&AudioStreamContainer::Play),
199 base::Unretained(stream_.get())));
200 return true;
203 void AudioStreamHandler::Stop() {
204 DCHECK(CalledOnValidThread());
205 AudioManager::Get()->GetTaskRunner()->PostTask(
206 FROM_HERE,
207 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
210 // static
211 void AudioStreamHandler::SetObserverForTesting(TestObserver* observer) {
212 g_observer_for_testing = observer;
215 // static
216 void AudioStreamHandler::SetAudioSourceForTesting(
217 AudioOutputStream::AudioSourceCallback* source) {
218 g_audio_source_for_testing = source;
221 } // namespace media