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: 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 41 virtual ~AudioStreamContainer() { 42 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread()); 43 } 44 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 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. 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 102 virtual int OnMoreIOData(AudioBus* /* source */, 103 AudioBus* dest, 104 AudioBuffersState state) OVERRIDE { 105 return OnMoreData(dest, state); 106 } 107 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 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 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 152 bool AudioStreamHandler::IsInitialized() const { 153 DCHECK(CalledOnValidThread()); 154 return initialized_; 155 } 156 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 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 178 void AudioStreamHandler::SetObserverForTesting(TestObserver* observer) { 179 g_observer_for_testing = observer; 180 } 181 182 // static 183 void AudioStreamHandler::SetAudioSourceForTesting( 184 AudioOutputStream::AudioSourceCallback* source) { 185 g_audio_source_for_testing = source; 186 } 187 188 } // namespace media 189