Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / media / audio / sounds / audio_stream_handler.cc
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:
39   AudioStreamContainer(const WavAudioHandler& wav_audio)
40       : stream_(NULL),
41         wav_audio_(wav_audio),
42         cursor_(0),
43         started_(false),
44         delayed_stop_posted_(false) {
45   }
46
47   virtual ~AudioStreamContainer() {
48     DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
49   }
50
51   void Play() {
52     DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
53
54     if (!stream_) {
55       const AudioParameters& p = wav_audio_.params();
56       const AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
57                                    p.channel_layout(),
58                                    p.sample_rate(),
59                                    p.bits_per_sample(),
60                                    kDefaultFrameCount);
61       stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(
62           params, std::string());
63       if (!stream_ || !stream_->Open()) {
64         LOG(ERROR) << "Failed to open an output stream.";
65         return;
66       }
67       stream_->SetVolume(kOutputVolumePercent);
68     }
69
70     {
71       base::AutoLock al(state_lock_);
72
73       delayed_stop_posted_ = false;
74       stop_closure_.Reset(base::Bind(
75           &AudioStreamContainer::StopStream, base::Unretained(this)));
76
77       if (started_) {
78         if (wav_audio_.AtEnd(cursor_))
79           cursor_ = 0;
80         return;
81       }
82
83       cursor_ = 0;
84       started_ = true;
85     }
86
87     if (g_audio_source_for_testing)
88       stream_->Start(g_audio_source_for_testing);
89     else
90       stream_->Start(this);
91
92     if (g_observer_for_testing)
93       g_observer_for_testing->OnPlay();
94   }
95
96   void Stop() {
97     DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
98     StopStream();
99     if (stream_)
100       stream_->Close();
101     stream_ = NULL;
102   }
103
104  private:
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;
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
127   virtual int OnMoreIOData(AudioBus* /* source */,
128                            AudioBus* dest,
129                            AudioBuffersState state) OVERRIDE {
130     return OnMoreData(dest, state);
131   }
132
133   virtual void OnError(AudioOutputStream* /* stream */) OVERRIDE {
134     LOG(ERROR) << "Error during system sound reproduction.";
135   }
136
137   void StopStream() {
138     DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
139
140     base::AutoLock al(state_lock_);
141
142     if (stream_ && started_) {
143       stream_->Stop();
144       if (g_observer_for_testing)
145         g_observer_for_testing->OnStop(cursor_);
146     }
147     started_ = false;
148   }
149
150   AudioOutputStream* stream_;
151
152   const WavAudioHandler wav_audio_;
153
154   base::Lock state_lock_;
155   size_t cursor_;
156   bool started_;
157   bool delayed_stop_posted_;
158   base::CancelableClosure stop_closure_;
159
160   DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
161 };
162
163 AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data)
164     : wav_audio_(wav_data),
165       initialized_(false) {
166   AudioManager* manager = AudioManager::Get();
167   if (!manager) {
168     LOG(ERROR) << "Can't get access to audio manager.";
169     return;
170   }
171   if (!wav_audio_.params().IsValid()) {
172     LOG(ERROR) << "Audio params are invalid.";
173     return;
174   }
175   stream_.reset(new AudioStreamContainer(wav_audio_));
176   initialized_ = true;
177 }
178
179 AudioStreamHandler::~AudioStreamHandler() {
180   DCHECK(CalledOnValidThread());
181   AudioManager::Get()->GetTaskRunner()->PostTask(
182       FROM_HERE,
183       base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
184   AudioManager::Get()->GetTaskRunner()->DeleteSoon(FROM_HERE,
185                                                    stream_.release());
186 }
187
188 bool AudioStreamHandler::IsInitialized() const {
189   DCHECK(CalledOnValidThread());
190   return initialized_;
191 }
192
193 bool AudioStreamHandler::Play() {
194   DCHECK(CalledOnValidThread());
195
196   if (!IsInitialized())
197     return false;
198
199   AudioManager::Get()->GetTaskRunner()->PostTask(
200       FROM_HERE,
201       base::Bind(base::IgnoreResult(&AudioStreamContainer::Play),
202                  base::Unretained(stream_.get())));
203   return true;
204 }
205
206 void AudioStreamHandler::Stop() {
207   DCHECK(CalledOnValidThread());
208   AudioManager::Get()->GetTaskRunner()->PostTask(
209       FROM_HERE,
210       base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
211 }
212
213 // static
214 void AudioStreamHandler::SetObserverForTesting(TestObserver* observer) {
215   g_observer_for_testing = observer;
216 }
217
218 // static
219 void AudioStreamHandler::SetAudioSourceForTesting(
220     AudioOutputStream::AudioSourceCallback* source) {
221   g_audio_source_for_testing = source;
222 }
223
224 }  // namespace media