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