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)
41 wav_audio_(wav_audio),
44 delayed_stop_posted_(false) {
47 virtual ~AudioStreamContainer() {
48 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
52 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
55 const AudioParameters& p = wav_audio_.params();
56 const AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
61 stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(
62 params, std::string());
63 if (!stream_ || !stream_->Open()) {
64 LOG(ERROR) << "Failed to open an output stream.";
67 stream_->SetVolume(kOutputVolumePercent);
71 base::AutoLock al(state_lock_);
73 delayed_stop_posted_ = false;
74 stop_closure_.Reset(base::Bind(
75 &AudioStreamContainer::StopStream, base::Unretained(this)));
78 if (wav_audio_.AtEnd(cursor_))
87 if (g_audio_source_for_testing)
88 stream_->Start(g_audio_source_for_testing);
92 if (g_observer_for_testing)
93 g_observer_for_testing->OnPlay();
97 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
105 // AudioOutputStream::AudioSourceCallback overrides:
106 // Following methods could be called from *ANY* thread.
107 virtual int OnMoreData(AudioBus* dest,
108 AudioBuffersState /* state */) OVERRIDE {
109 base::AutoLock al(state_lock_);
110 size_t bytes_written = 0;
112 if (wav_audio_.AtEnd(cursor_) ||
113 !wav_audio_.CopyTo(dest, cursor_, &bytes_written)) {
114 if (delayed_stop_posted_)
116 delayed_stop_posted_ = true;
117 AudioManager::Get()->GetTaskRunner()->PostDelayedTask(
119 stop_closure_.callback(),
120 base::TimeDelta::FromMilliseconds(kKeepAliveMs));
123 cursor_ += bytes_written;
124 return dest->frames();
127 virtual int OnMoreIOData(AudioBus* /* source */,
129 AudioBuffersState state) OVERRIDE {
130 return OnMoreData(dest, state);
133 virtual void OnError(AudioOutputStream* /* stream */) OVERRIDE {
134 LOG(ERROR) << "Error during system sound reproduction.";
138 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
140 base::AutoLock al(state_lock_);
142 if (stream_ && started_) {
144 if (g_observer_for_testing)
145 g_observer_for_testing->OnStop(cursor_);
150 AudioOutputStream* stream_;
152 const WavAudioHandler wav_audio_;
154 base::Lock state_lock_;
157 bool delayed_stop_posted_;
158 base::CancelableClosure stop_closure_;
160 DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
163 AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data)
164 : wav_audio_(wav_data),
165 initialized_(false) {
166 AudioManager* manager = AudioManager::Get();
168 LOG(ERROR) << "Can't get access to audio manager.";
171 if (!wav_audio_.params().IsValid()) {
172 LOG(ERROR) << "Audio params are invalid.";
175 stream_.reset(new AudioStreamContainer(wav_audio_));
179 AudioStreamHandler::~AudioStreamHandler() {
180 DCHECK(CalledOnValidThread());
181 AudioManager::Get()->GetTaskRunner()->PostTask(
183 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
184 AudioManager::Get()->GetTaskRunner()->DeleteSoon(FROM_HERE,
188 bool AudioStreamHandler::IsInitialized() const {
189 DCHECK(CalledOnValidThread());
193 bool AudioStreamHandler::Play() {
194 DCHECK(CalledOnValidThread());
196 if (!IsInitialized())
199 AudioManager::Get()->GetTaskRunner()->PostTask(
201 base::Bind(base::IgnoreResult(&AudioStreamContainer::Play),
202 base::Unretained(stream_.get())));
206 void AudioStreamHandler::Stop() {
207 DCHECK(CalledOnValidThread());
208 AudioManager::Get()->GetTaskRunner()->PostTask(
210 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
214 void AudioStreamHandler::SetObserverForTesting(TestObserver* observer) {
215 g_observer_for_testing = observer;
219 void AudioStreamHandler::SetAudioSourceForTesting(
220 AudioOutputStream::AudioSourceCallback* source) {
221 g_audio_source_for_testing = source;