1 // Copyright 2014 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/copresence/mediums/audio/audio_player.h"
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/copresence/public/copresence_constants.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"
22 const int kDefaultFrameCount
= 1024;
23 const double kOutputVolumePercent
= 1.0f
;
27 namespace copresence
{
31 AudioPlayer::AudioPlayer()
32 : is_playing_(false), stream_(NULL
), frame_index_(0) {
35 AudioPlayer::~AudioPlayer() {
38 void AudioPlayer::Initialize() {
39 media::AudioManager::Get()->GetTaskRunner()->PostTask(
41 base::Bind(&AudioPlayer::InitializeOnAudioThread
,
42 base::Unretained(this)));
45 void AudioPlayer::Play(
46 const scoped_refptr
<media::AudioBusRefCounted
>& samples
) {
47 media::AudioManager::Get()->GetTaskRunner()->PostTask(
50 &AudioPlayer::PlayOnAudioThread
, base::Unretained(this), samples
));
53 void AudioPlayer::Stop() {
54 media::AudioManager::Get()->GetTaskRunner()->PostTask(
56 base::Bind(&AudioPlayer::StopOnAudioThread
, base::Unretained(this)));
59 bool AudioPlayer::IsPlaying() {
63 void AudioPlayer::Finalize() {
64 media::AudioManager::Get()->GetTaskRunner()->PostTask(
66 base::Bind(&AudioPlayer::FinalizeOnAudioThread
, base::Unretained(this)));
71 void AudioPlayer::InitializeOnAudioThread() {
72 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
73 stream_
= output_stream_for_testing_
74 ? output_stream_for_testing_
.get()
75 : media::AudioManager::Get()->MakeAudioOutputStreamProxy(
76 media::AudioParameters(
77 media::AudioParameters::AUDIO_PCM_LOW_LATENCY
,
78 media::CHANNEL_LAYOUT_MONO
,
80 kDefaultBitsPerSample
,
84 if (!stream_
|| !stream_
->Open()) {
85 LOG(ERROR
) << "Failed to open an output stream.";
92 stream_
->SetVolume(kOutputVolumePercent
);
95 void AudioPlayer::PlayOnAudioThread(
96 const scoped_refptr
<media::AudioBusRefCounted
>& samples
) {
97 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
102 base::AutoLock
al(state_lock_
);
112 stream_
->Start(this);
115 void AudioPlayer::StopOnAudioThread() {
116 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
124 void AudioPlayer::StopAndCloseOnAudioThread() {
125 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
137 void AudioPlayer::FinalizeOnAudioThread() {
138 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
139 StopAndCloseOnAudioThread();
143 int AudioPlayer::OnMoreData(media::AudioBus
* dest
,
144 media::AudioBuffersState
/* state */) {
145 base::AutoLock
al(state_lock_
);
146 // Continuously play our samples till explicitly told to stop.
147 const int leftover_frames
= samples_
->frames() - frame_index_
;
148 const int frames_to_copy
= std::min(dest
->frames(), leftover_frames
);
150 samples_
->CopyPartialFramesTo(frame_index_
, frames_to_copy
, 0, dest
);
151 frame_index_
+= frames_to_copy
;
153 // If we didn't fill the destination audio bus, wrap around and fill the rest.
154 if (leftover_frames
<= dest
->frames()) {
155 samples_
->CopyPartialFramesTo(
156 0, dest
->frames() - frames_to_copy
, frames_to_copy
, dest
);
157 frame_index_
= dest
->frames() - frames_to_copy
;
160 return dest
->frames();
163 void AudioPlayer::OnError(media::AudioOutputStream
* /* stream */) {
164 LOG(ERROR
) << "Error during system sound reproduction.";
165 media::AudioManager::Get()->GetTaskRunner()->PostTask(
167 base::Bind(&AudioPlayer::StopAndCloseOnAudioThread
,
168 base::Unretained(this)));
171 void AudioPlayer::FlushAudioLoopForTesting() {
172 if (media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread())
175 // Queue task on the audio thread, when it is executed, that means we've
176 // successfully executed all the tasks before us.
178 media::AudioManager::Get()->GetTaskRunner()->PostTaskAndReply(
180 base::Bind(base::IgnoreResult(&AudioPlayer::FlushAudioLoopForTesting
),
181 base::Unretained(this)),
186 } // namespace copresence