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.
4
5 #include "media/audio/sounds/audio_stream_handler.h"
6
7 #include <string>
8
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"
17
18 namespace media {
19
20 namespace {
21
22 // Volume percent.
23 const double kOutputVolumePercent = 0.8;
24
25 // The number of frames each OnMoreData() call will request.
26 const int kDefaultFrameCount = 1024;
27
28 // Keep alive timeout for audio stream.
29 const int kKeepAliveMs = 1500;
30
31 AudioStreamHandler::TestObserver* g_observer_for_testing = NULL;
32 AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL;
33
34 } // namespace
35
36 class AudioStreamHandler::AudioStreamContainer
37 : public AudioOutputStream::AudioSourceCallback {
38 public:
AudioStreamContainer(const WavAudioHandler & wav_audio)39 AudioStreamContainer(const WavAudioHandler& wav_audio)
40 : started_(false),
41 stream_(NULL),
42 cursor_(0),
43 delayed_stop_posted_(false),
44 wav_audio_(wav_audio) {}
45
~AudioStreamContainer()46 virtual ~AudioStreamContainer() {
47 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
48 }
49
Play()50 void Play() {
51 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
52
53 if (!stream_) {
54 const AudioParameters& p = wav_audio_.params();
55 const AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
56 p.channel_layout(),
57 p.sample_rate(),
58 p.bits_per_sample(),
59 kDefaultFrameCount);
60 stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(params,
61 std::string());
62 if (!stream_ || !stream_->Open()) {
63 LOG(ERROR) << "Failed to open an output stream.";
64 return;
65 }
66 stream_->SetVolume(kOutputVolumePercent);
67 }
68
69 {
70 base::AutoLock al(state_lock_);
71
72 delayed_stop_posted_ = false;
73 stop_closure_.Reset(base::Bind(&AudioStreamContainer::StopStream,
74 base::Unretained(this)));
75
76 if (started_) {
77 if (wav_audio_.AtEnd(cursor_))
78 cursor_ = 0;
79 return;
80 }
81
82 cursor_ = 0;
83 }
84
85 started_ = true;
86 if (g_audio_source_for_testing)
87 stream_->Start(g_audio_source_for_testing);
88 else
89 stream_->Start(this);
90
91 if (g_observer_for_testing)
92 g_observer_for_testing->OnPlay();
93 }
94
Stop()95 void Stop() {
96 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
97 StopStream();
98 if (stream_)
99 stream_->Close();
100 stream_ = NULL;
101 stop_closure_.Cancel();
102 }
103
104 private:
105 // AudioOutputStream::AudioSourceCallback overrides:
106 // Following methods could be called from *ANY* thread.
OnMoreData(AudioBus * dest,AudioBuffersState)107 virtual int OnMoreData(AudioBus* dest,
108 AudioBuffersState /* state */) OVERRIDE {
109 base::AutoLock al(state_lock_);
110 size_t bytes_written = 0;
111
112 if (wav_audio_.AtEnd(cursor_) ||
113 !wav_audio_.CopyTo(dest, cursor_, &bytes_written)) {
114 if (delayed_stop_posted_)
115 return 0;
116 delayed_stop_posted_ = true;
117 AudioManager::Get()->GetTaskRunner()->PostDelayedTask(
118 FROM_HERE,
119 stop_closure_.callback(),
120 base::TimeDelta::FromMilliseconds(kKeepAliveMs));
121 return 0;
122 }
123 cursor_ += bytes_written;
124 return dest->frames();
125 }
126
OnError(AudioOutputStream *)127 virtual void OnError(AudioOutputStream* /* stream */) OVERRIDE {
128 LOG(ERROR) << "Error during system sound reproduction.";
129 }
130
StopStream()131 void StopStream() {
132 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
133
134 if (stream_ && started_) {
135 // Do not hold the |state_lock_| while stopping the output stream.
136 stream_->Stop();
137 if (g_observer_for_testing)
138 g_observer_for_testing->OnStop(cursor_);
139 }
140
141 started_ = false;
142 }
143
144 // Must only be accessed on the AudioManager::GetTaskRunner() thread.
145 bool started_;
146 AudioOutputStream* stream_;
147
148 // All variables below must be accessed under |state_lock_| when |started_|.
149 base::Lock state_lock_;
150 size_t cursor_;
151 bool delayed_stop_posted_;
152 const WavAudioHandler wav_audio_;
153 base::CancelableClosure stop_closure_;
154
155 DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
156 };
157
AudioStreamHandler(const base::StringPiece & wav_data)158 AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data)
159 : wav_audio_(wav_data),
160 initialized_(false) {
161 AudioManager* manager = AudioManager::Get();
162 if (!manager) {
163 LOG(ERROR) << "Can't get access to audio manager.";
164 return;
165 }
166 if (!wav_audio_.params().IsValid()) {
167 LOG(ERROR) << "Audio params are invalid.";
168 return;
169 }
170 stream_.reset(new AudioStreamContainer(wav_audio_));
171 initialized_ = true;
172 }
173
~AudioStreamHandler()174 AudioStreamHandler::~AudioStreamHandler() {
175 DCHECK(CalledOnValidThread());
176 AudioManager::Get()->GetTaskRunner()->PostTask(
177 FROM_HERE,
178 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
179 AudioManager::Get()->GetTaskRunner()->DeleteSoon(FROM_HERE,
180 stream_.release());
181 }
182
IsInitialized() const183 bool AudioStreamHandler::IsInitialized() const {
184 DCHECK(CalledOnValidThread());
185 return initialized_;
186 }
187
Play()188 bool AudioStreamHandler::Play() {
189 DCHECK(CalledOnValidThread());
190
191 if (!IsInitialized())
192 return false;
193
194 AudioManager::Get()->GetTaskRunner()->PostTask(
195 FROM_HERE,
196 base::Bind(base::IgnoreResult(&AudioStreamContainer::Play),
197 base::Unretained(stream_.get())));
198 return true;
199 }
200
Stop()201 void AudioStreamHandler::Stop() {
202 DCHECK(CalledOnValidThread());
203 AudioManager::Get()->GetTaskRunner()->PostTask(
204 FROM_HERE,
205 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
206 }
207
208 // static
SetObserverForTesting(TestObserver * observer)209 void AudioStreamHandler::SetObserverForTesting(TestObserver* observer) {
210 g_observer_for_testing = observer;
211 }
212
213 // static
SetAudioSourceForTesting(AudioOutputStream::AudioSourceCallback * source)214 void AudioStreamHandler::SetAudioSourceForTesting(
215 AudioOutputStream::AudioSourceCallback* source) {
216 g_audio_source_for_testing = source;
217 }
218
219 } // namespace media
220