audio_player.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved. 21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be 31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file. 41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/copresence/mediums/audio/audio_player.h" 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <algorithm> 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <vector> 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind.h" 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind_helpers.h" 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/logging.h" 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/run_loop.h" 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/copresence/public/copresence_constants.h" 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/browser_thread.h" 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "media/audio/audio_manager.h" 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "media/audio/audio_parameters.h" 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "media/base/audio_bus.h" 191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace { 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 22const int kDefaultFrameCount = 1024; 23const double kOutputVolumePercent = 1.0f; 24 25} // namespace 26 27namespace copresence { 28 29// Public methods. 30 31AudioPlayer::AudioPlayer() 32 : stream_(NULL), is_playing_(false), frame_index_(0) { 33} 34 35AudioPlayer::~AudioPlayer() { 36} 37 38void AudioPlayer::Initialize() { 39 media::AudioManager::Get()->GetTaskRunner()->PostTask( 40 FROM_HERE, 41 base::Bind(&AudioPlayer::InitializeOnAudioThread, 42 base::Unretained(this))); 43} 44 45void AudioPlayer::Play( 46 const scoped_refptr<media::AudioBusRefCounted>& samples) { 47 media::AudioManager::Get()->GetTaskRunner()->PostTask( 48 FROM_HERE, 49 base::Bind( 50 &AudioPlayer::PlayOnAudioThread, base::Unretained(this), samples)); 51} 52 53void AudioPlayer::Stop() { 54 media::AudioManager::Get()->GetTaskRunner()->PostTask( 55 FROM_HERE, 56 base::Bind(&AudioPlayer::StopOnAudioThread, base::Unretained(this))); 57} 58 59void AudioPlayer::Finalize() { 60 media::AudioManager::Get()->GetTaskRunner()->PostTask( 61 FROM_HERE, 62 base::Bind(&AudioPlayer::FinalizeOnAudioThread, base::Unretained(this))); 63} 64 65// Private methods. 66 67void AudioPlayer::InitializeOnAudioThread() { 68 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 69 stream_ = output_stream_for_testing_ 70 ? output_stream_for_testing_.get() 71 : media::AudioManager::Get()->MakeAudioOutputStreamProxy( 72 media::AudioParameters( 73 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 74 media::CHANNEL_LAYOUT_MONO, 75 kDefaultSampleRate, 76 kDefaultBitsPerSample, 77 kDefaultFrameCount), 78 std::string()); 79 80 if (!stream_ || !stream_->Open()) { 81 LOG(ERROR) << "Failed to open an output stream."; 82 if (stream_) { 83 stream_->Close(); 84 stream_ = NULL; 85 } 86 return; 87 } 88 stream_->SetVolume(kOutputVolumePercent); 89} 90 91void AudioPlayer::PlayOnAudioThread( 92 const scoped_refptr<media::AudioBusRefCounted>& samples) { 93 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 94 if (!stream_) 95 return; 96 97 { 98 base::AutoLock al(state_lock_); 99 100 samples_ = samples; 101 frame_index_ = 0; 102 103 if (is_playing_) 104 return; 105 } 106 107 DVLOG(2) << "Playing Audio."; 108 is_playing_ = true; 109 stream_->Start(this); 110} 111 112void AudioPlayer::StopOnAudioThread() { 113 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 114 if (!stream_) 115 return; 116 117 stream_->Stop(); 118 is_playing_ = false; 119} 120 121void AudioPlayer::StopAndCloseOnAudioThread() { 122 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 123 if (!stream_) 124 return; 125 126 if (is_playing_) 127 stream_->Stop(); 128 stream_->Close(); 129 stream_ = NULL; 130 131 is_playing_ = false; 132} 133 134void AudioPlayer::FinalizeOnAudioThread() { 135 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 136 StopAndCloseOnAudioThread(); 137 delete this; 138} 139 140int AudioPlayer::OnMoreData(media::AudioBus* dest, 141 media::AudioBuffersState /* state */) { 142 base::AutoLock al(state_lock_); 143 // Continuously play our samples till explicitly told to stop. 144 const int leftover_frames = samples_->frames() - frame_index_; 145 const int frames_to_copy = std::min(dest->frames(), leftover_frames); 146 147 samples_->CopyPartialFramesTo(frame_index_, frames_to_copy, 0, dest); 148 frame_index_ += frames_to_copy; 149 150 // If we didn't fill the destination audio bus, wrap around and fill the rest. 151 if (leftover_frames <= dest->frames()) { 152 samples_->CopyPartialFramesTo( 153 0, dest->frames() - frames_to_copy, frames_to_copy, dest); 154 frame_index_ = dest->frames() - frames_to_copy; 155 } 156 157 return dest->frames(); 158} 159 160void AudioPlayer::OnError(media::AudioOutputStream* /* stream */) { 161 LOG(ERROR) << "Error during system sound reproduction."; 162 media::AudioManager::Get()->GetTaskRunner()->PostTask( 163 FROM_HERE, 164 base::Bind(&AudioPlayer::StopAndCloseOnAudioThread, 165 base::Unretained(this))); 166} 167 168void AudioPlayer::FlushAudioLoopForTesting() { 169 if (media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()) 170 return; 171 172 // Queue task on the audio thread, when it is executed, that means we've 173 // successfully executed all the tasks before us. 174 base::RunLoop rl; 175 media::AudioManager::Get()->GetTaskRunner()->PostTaskAndReply( 176 FROM_HERE, 177 base::Bind(base::IgnoreResult(&AudioPlayer::FlushAudioLoopForTesting), 178 base::Unretained(this)), 179 rl.QuitClosure()); 180 rl.Run(); 181} 182 183} // namespace copresence 184