- add sources.
[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/logging.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "media/audio/audio_manager.h"
12 #include "media/audio/audio_manager_base.h"
13 #include "media/base/channel_layout.h"
14
15 namespace media {
16
17 namespace {
18
19 // Volume percent.
20 const double kOutputVolumePercent = 0.8;
21
22 AudioStreamHandler::TestObserver* g_observer_for_testing = NULL;
23 AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL;
24
25 }  // namespace
26
27 class AudioStreamHandler::AudioStreamContainer
28     : public AudioOutputStream::AudioSourceCallback {
29  public:
30   AudioStreamContainer(const WavAudioHandler& wav_audio,
31                        const AudioParameters& params)
32       : stream_(NULL),
33         wav_audio_(wav_audio),
34         params_(params),
35         cursor_(0) {
36   }
37
38   virtual ~AudioStreamContainer() {
39     DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
40   }
41
42   void Play() {
43     DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
44
45     if (!stream_) {
46       stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(params_,
47                                                                 std::string(),
48                                                                 std::string());
49       if (!stream_ || !stream_->Open()) {
50         LOG(ERROR) << "Failed to open an output stream.";
51         return;
52       }
53       stream_->SetVolume(kOutputVolumePercent);
54     } else {
55       // TODO (ygorshenin@): implement smart stream rewind.
56       stream_->Stop();
57     }
58
59     cursor_ = 0;
60     if (g_audio_source_for_testing)
61       stream_->Start(g_audio_source_for_testing);
62     else
63       stream_->Start(this);
64
65     if (g_observer_for_testing)
66       g_observer_for_testing->OnPlay();
67   }
68
69   void Stop() {
70     DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
71     if (!stream_)
72       return;
73     stream_->Stop();
74     stream_->Close();
75     stream_ = NULL;
76
77     if (g_observer_for_testing)
78       g_observer_for_testing->OnStop(cursor_);
79   }
80
81  private:
82   // AudioOutputStream::AudioSourceCallback overrides:
83   // Following methods could be called from *ANY* thread.
84   virtual int OnMoreData(AudioBus* dest,
85                          AudioBuffersState /* state */) OVERRIDE {
86     size_t bytes_written = 0;
87     if (wav_audio_.AtEnd(cursor_) ||
88         !wav_audio_.CopyTo(dest, cursor_, &bytes_written)) {
89       AudioManager::Get()->GetMessageLoop()->PostTask(
90           FROM_HERE,
91           base::Bind(&AudioStreamContainer::Stop, base::Unretained(this)));
92       return 0;
93     }
94     cursor_ += bytes_written;
95
96     return dest->frames();
97   }
98
99   virtual int OnMoreIOData(AudioBus* /* source */,
100                            AudioBus* dest,
101                            AudioBuffersState state) OVERRIDE {
102     return OnMoreData(dest, state);
103   }
104
105   virtual void OnError(AudioOutputStream* /* stream */) OVERRIDE {
106     LOG(ERROR) << "Error during system sound reproduction.";
107   }
108
109   AudioOutputStream* stream_;
110
111   const WavAudioHandler wav_audio_;
112   const AudioParameters params_;
113
114   size_t cursor_;
115
116   DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
117 };
118
119 AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data)
120     : wav_audio_(wav_data),
121       initialized_(false) {
122   AudioManager* manager = AudioManager::Get();
123   if (!manager) {
124     LOG(ERROR) << "Can't get access to audio manager.";
125     return;
126   }
127   AudioParameters params(
128       AudioParameters::AUDIO_PCM_LOW_LATENCY,
129       GuessChannelLayout(wav_audio_.num_channels()),
130       wav_audio_.sample_rate(),
131       wav_audio_.bits_per_sample(),
132       manager->GetDefaultOutputStreamParameters().frames_per_buffer());
133   if (!params.IsValid()) {
134     LOG(ERROR) << "Audio params are invalid.";
135     return;
136   }
137   stream_.reset(new AudioStreamContainer(wav_audio_, params));
138   initialized_ = true;
139 }
140
141 AudioStreamHandler::~AudioStreamHandler() {
142   DCHECK(CalledOnValidThread());
143   AudioManager::Get()->GetMessageLoop()->PostTask(
144       FROM_HERE,
145       base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
146   AudioManager::Get()->GetMessageLoop()->DeleteSoon(FROM_HERE,
147                                                     stream_.release());
148 }
149
150 bool AudioStreamHandler::IsInitialized() const {
151   DCHECK(CalledOnValidThread());
152   return initialized_;
153 }
154
155 bool AudioStreamHandler::Play() {
156   DCHECK(CalledOnValidThread());
157
158   if (!IsInitialized())
159     return false;
160
161   AudioManager::Get()->GetMessageLoop()->PostTask(
162       FROM_HERE,
163       base::Bind(base::IgnoreResult(&AudioStreamContainer::Play),
164                  base::Unretained(stream_.get())));
165   return true;
166 }
167
168 void AudioStreamHandler::Stop() {
169   DCHECK(CalledOnValidThread());
170   AudioManager::Get()->GetMessageLoop()->PostTask(
171       FROM_HERE,
172       base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
173 }
174
175 // static
176 void AudioStreamHandler::SetObserverForTesting(TestObserver* observer) {
177   g_observer_for_testing = observer;
178 }
179
180 // static
181 void AudioStreamHandler::SetAudioSourceForTesting(
182     AudioOutputStream::AudioSourceCallback* source) {
183   g_audio_source_for_testing = source;
184 }
185
186 }  // namespace media