Fix crash in ResourceLoader if the resources were retrieved before BlockUntilLoaded...
[chromium-blink-merge.git] / components / audio_modem / audio_player_impl.cc
blob22fd723b6b89193187d63717be383dfbb2dc7043
1 // Copyright 2015 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.
5 #include "components/audio_modem/audio_player_impl.h"
7 #include <algorithm>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/logging.h"
13 #include "base/run_loop.h"
14 #include "components/audio_modem/public/audio_modem_types.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "media/audio/audio_manager.h"
17 #include "media/audio/audio_parameters.h"
18 #include "media/base/audio_bus.h"
20 namespace {
22 const int kDefaultFrameCount = 1024;
23 const double kOutputVolumePercent = 1.0f;
25 } // namespace
27 namespace audio_modem {
29 // Public methods.
31 AudioPlayerImpl::AudioPlayerImpl()
32 : is_playing_(false), stream_(nullptr), frame_index_(0) {
35 AudioPlayerImpl::~AudioPlayerImpl() {
38 void AudioPlayerImpl::Initialize() {
39 media::AudioManager::Get()->GetTaskRunner()->PostTask(
40 FROM_HERE,
41 base::Bind(&AudioPlayerImpl::InitializeOnAudioThread,
42 base::Unretained(this)));
45 void AudioPlayerImpl::Play(
46 const scoped_refptr<media::AudioBusRefCounted>& samples) {
47 media::AudioManager::Get()->GetTaskRunner()->PostTask(
48 FROM_HERE,
49 base::Bind(&AudioPlayerImpl::PlayOnAudioThread,
50 base::Unretained(this),
51 samples));
54 void AudioPlayerImpl::Stop() {
55 media::AudioManager::Get()->GetTaskRunner()->PostTask(
56 FROM_HERE,
57 base::Bind(&AudioPlayerImpl::StopOnAudioThread, base::Unretained(this)));
60 void AudioPlayerImpl::Finalize() {
61 media::AudioManager::Get()->GetTaskRunner()->PostTask(
62 FROM_HERE,
63 base::Bind(&AudioPlayerImpl::FinalizeOnAudioThread,
64 base::Unretained(this)));
67 // Private methods.
69 void AudioPlayerImpl::InitializeOnAudioThread() {
70 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
71 stream_ = output_stream_for_testing_
72 ? output_stream_for_testing_.get()
73 : media::AudioManager::Get()->MakeAudioOutputStreamProxy(
74 media::AudioParameters(
75 media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
76 media::CHANNEL_LAYOUT_MONO,
77 kDefaultSampleRate,
78 kDefaultBitsPerSample,
79 kDefaultFrameCount),
80 std::string());
82 if (!stream_ || !stream_->Open()) {
83 LOG(ERROR) << "Failed to open an output stream.";
84 if (stream_) {
85 stream_->Close();
86 stream_ = nullptr;
88 return;
90 stream_->SetVolume(kOutputVolumePercent);
93 void AudioPlayerImpl::PlayOnAudioThread(
94 const scoped_refptr<media::AudioBusRefCounted>& samples) {
95 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
96 if (!stream_ || is_playing_)
97 return;
100 base::AutoLock al(state_lock_);
101 samples_ = samples;
102 frame_index_ = 0;
105 VLOG(3) << "Starting playback.";
106 is_playing_ = true;
107 stream_->Start(this);
110 void AudioPlayerImpl::StopOnAudioThread() {
111 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
112 if (!stream_ || !is_playing_)
113 return;
115 VLOG(3) << "Stopping playback.";
116 stream_->Stop();
117 is_playing_ = false;
120 void AudioPlayerImpl::StopAndCloseOnAudioThread() {
121 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
122 if (!stream_)
123 return;
125 StopOnAudioThread();
126 stream_->Close();
127 stream_ = nullptr;
130 void AudioPlayerImpl::FinalizeOnAudioThread() {
131 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
132 StopAndCloseOnAudioThread();
133 delete this;
136 int AudioPlayerImpl::OnMoreData(media::AudioBus* dest,
137 uint32 /* total_bytes_delay */) {
138 base::AutoLock al(state_lock_);
139 // Continuously play our samples till explicitly told to stop.
140 const int leftover_frames = samples_->frames() - frame_index_;
141 const int frames_to_copy = std::min(dest->frames(), leftover_frames);
143 samples_->CopyPartialFramesTo(frame_index_, frames_to_copy, 0, dest);
144 frame_index_ += frames_to_copy;
146 // If we didn't fill the destination audio bus, wrap around and fill the rest.
147 if (leftover_frames <= dest->frames()) {
148 samples_->CopyPartialFramesTo(
149 0, dest->frames() - frames_to_copy, frames_to_copy, dest);
150 frame_index_ = dest->frames() - frames_to_copy;
153 return dest->frames();
156 void AudioPlayerImpl::OnError(media::AudioOutputStream* /* stream */) {
157 LOG(ERROR) << "Error during system sound reproduction.";
158 media::AudioManager::Get()->GetTaskRunner()->PostTask(
159 FROM_HERE,
160 base::Bind(&AudioPlayerImpl::StopAndCloseOnAudioThread,
161 base::Unretained(this)));
164 void AudioPlayerImpl::FlushAudioLoopForTesting() {
165 if (media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread())
166 return;
168 // Queue task on the audio thread, when it is executed, that means we've
169 // successfully executed all the tasks before us.
170 base::RunLoop rl;
171 media::AudioManager::Get()->GetTaskRunner()->PostTaskAndReply(
172 FROM_HERE,
173 base::Bind(base::IgnoreResult(&AudioPlayerImpl::FlushAudioLoopForTesting),
174 base::Unretained(this)),
175 rl.QuitClosure());
176 rl.Run();
179 } // namespace audio_modem