audio_stream_handler.cc revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
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 15namespace media { 16 17namespace { 18 19// Volume percent. 20const double kOutputVolumePercent = 0.8; 21 22AudioStreamHandler::TestObserver* g_observer_for_testing = NULL; 23AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL; 24 25} // namespace 26 27class 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 119AudioStreamHandler::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 141AudioStreamHandler::~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 150bool AudioStreamHandler::IsInitialized() const { 151 DCHECK(CalledOnValidThread()); 152 return initialized_; 153} 154 155bool 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 168void 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 176void AudioStreamHandler::SetObserverForTesting(TestObserver* observer) { 177 g_observer_for_testing = observer; 178} 179 180// static 181void AudioStreamHandler::SetAudioSourceForTesting( 182 AudioOutputStream::AudioSourceCallback* source) { 183 g_audio_source_for_testing = source; 184} 185 186} // namespace media 187