OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "components/copresence/mediums/audio/audio_player.h" | |
6 | |
7 #include <algorithm> | |
8 #include <vector> | |
9 | |
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/common/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" | |
19 | |
20 namespace { | |
21 | |
22 const int kDefaultFrameCount = 1024; | |
23 const double kOutputVolumePercent = 1.0; | |
24 } | |
xiyuan
2014/07/25 21:02:10
nit: insert an empty line before and add " // nam
rkc
2014/07/28 21:02:02
Done.
| |
25 | |
26 namespace copresence { | |
27 | |
28 // Public methods. | |
29 | |
30 AudioPlayer::AudioPlayer() | |
31 : stream_(NULL), | |
32 frame_index_(0), | |
33 is_playing_(false), | |
34 output_stream_for_testing_(NULL) { | |
35 media::AudioManager::Get()->GetTaskRunner()->PostTask( | |
36 FROM_HERE, | |
37 base::Bind(&AudioPlayer::InitializeOnAudioThread, | |
38 base::Unretained(this))); | |
39 } | |
40 | |
41 AudioPlayer::~AudioPlayer() { | |
Daniel Erat
2014/07/28 21:18:18
please use the same order in the .cc file as in th
rkc
2014/07/29 00:33:35
Done.
| |
42 } | |
43 | |
44 AudioPlayer::AudioPlayer(media::AudioOutputStream* output_stream_for_testing) | |
45 : stream_(NULL), | |
46 frame_index_(0), | |
47 is_playing_(false), | |
48 output_stream_for_testing_(output_stream_for_testing) { | |
49 media::AudioManager::Get()->GetTaskRunner()->PostTask( | |
50 FROM_HERE, | |
51 base::Bind(&AudioPlayer::InitializeOnAudioThread, | |
Daniel Erat
2014/07/28 21:18:17
how about adding a separate Init() method that doe
rkc
2014/07/29 00:33:35
Done.
| |
52 base::Unretained(this))); | |
53 } | |
54 | |
55 void AudioPlayer::Play( | |
56 const scoped_refptr<media::AudioBusRefCounted>& samples) { | |
57 media::AudioManager::Get()->GetTaskRunner()->PostTask( | |
58 FROM_HERE, | |
59 base::Bind( | |
60 &AudioPlayer::PlayOnAudioThread, base::Unretained(this), samples)); | |
61 } | |
62 | |
63 void AudioPlayer::Stop() { | |
64 media::AudioManager::Get()->GetTaskRunner()->PostTask( | |
65 FROM_HERE, | |
66 base::Bind(&AudioPlayer::StopOnAudioThread, base::Unretained(this))); | |
67 } | |
68 | |
69 void AudioPlayer::Finalize() { | |
70 media::AudioManager::Get()->GetTaskRunner()->PostTask( | |
71 FROM_HERE, | |
72 base::Bind(&AudioPlayer::FinalizeOnAudioThread, base::Unretained(this))); | |
73 } | |
74 | |
75 // Private methods. | |
76 | |
77 void AudioPlayer::InitializeOnAudioThread() { | |
78 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | |
79 stream_ = output_stream_for_testing_ | |
80 ? output_stream_for_testing_ | |
81 : media::AudioManager::Get()->MakeAudioOutputStreamProxy( | |
82 media::AudioParameters( | |
83 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | |
84 media::CHANNEL_LAYOUT_MONO, | |
85 kDefaultSampleRate, | |
86 kDefaultBitsPerSample, | |
87 kDefaultFrameCount), | |
88 std::string()); | |
89 | |
90 if (!stream_ || !stream_->Open()) { | |
91 LOG(ERROR) << "Failed to open an output stream."; | |
92 if (stream_) { | |
93 stream_->Close(); | |
94 stream_ = NULL; | |
95 } | |
96 return; | |
97 } | |
98 stream_->SetVolume(kOutputVolumePercent); | |
99 } | |
100 | |
101 void AudioPlayer::PlayOnAudioThread( | |
102 const scoped_refptr<media::AudioBusRefCounted>& samples) { | |
103 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | |
104 if (!stream_) | |
105 return; | |
106 | |
107 { | |
108 base::AutoLock al(state_lock_); | |
109 | |
110 samples_ = samples; | |
111 frame_index_ = 0; | |
112 | |
113 if (is_playing_) | |
114 return; | |
115 } | |
116 | |
117 DVLOG(2) << "Playing Audio."; | |
118 is_playing_ = true; | |
Daniel Erat
2014/07/28 21:18:17
the header has a comment saying that all members a
rkc
2014/07/29 00:33:35
All the methods that must run on certain threads h
| |
119 stream_->Start(this); | |
120 } | |
121 | |
122 void AudioPlayer::StopOnAudioThread() { | |
123 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | |
124 if (!stream_) | |
125 return; | |
126 | |
127 stream_->Stop(); | |
128 is_playing_ = false; | |
129 } | |
130 | |
131 void AudioPlayer::StopAndCloseOnAudioThread() { | |
132 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | |
133 if (!stream_) | |
134 return; | |
135 | |
136 if (is_playing_) | |
137 stream_->Stop(); | |
138 stream_->Close(); | |
139 stream_ = NULL; | |
140 | |
141 is_playing_ = false; | |
142 } | |
143 | |
144 void AudioPlayer::FinalizeOnAudioThread() { | |
145 DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | |
146 StopAndCloseOnAudioThread(); | |
147 delete this; | |
148 } | |
149 | |
150 int AudioPlayer::OnMoreData(media::AudioBus* dest, | |
151 media::AudioBuffersState /* state */) { | |
152 base::AutoLock al(state_lock_); | |
153 DCHECK(is_playing_); | |
154 | |
155 // Continuously play our samples till explicitly told to stop. | |
156 const int leftover_frames = samples_->frames() - frame_index_; | |
157 const int frames_to_copy = std::min(dest->frames(), leftover_frames); | |
158 | |
159 samples_->CopyPartialFramesTo(frame_index_, frames_to_copy, 0, dest); | |
160 frame_index_ += frames_to_copy; | |
161 | |
162 // If we didn't fill the destination audio bus, wrap around and fill the rest. | |
163 if (leftover_frames <= dest->frames()) { | |
164 samples_->CopyPartialFramesTo( | |
165 0, dest->frames() - frames_to_copy, frames_to_copy, dest); | |
166 frame_index_ = dest->frames() - frames_to_copy; | |
167 } | |
168 | |
169 return dest->frames(); | |
170 } | |
171 | |
172 void AudioPlayer::OnError(media::AudioOutputStream* /* stream */) { | |
173 LOG(ERROR) << "Error during system sound reproduction."; | |
174 media::AudioManager::Get()->GetTaskRunner()->PostTask( | |
175 FROM_HERE, | |
176 base::Bind(&AudioPlayer::StopAndCloseOnAudioThread, | |
177 base::Unretained(this))); | |
178 } | |
179 | |
180 void AudioPlayer::FlushAudioLoop() { | |
181 if (media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()) | |
182 return; | |
183 | |
184 // All this does is flush the tasks on the audio thread. | |
185 base::RunLoop rl; | |
DaleCurtis
2014/07/25 20:41:29
This isn't allowed in production code. See base/r
rkc
2014/07/28 21:02:02
Done.
| |
186 media::AudioManager::Get()->GetTaskRunner()->PostTaskAndReply( | |
187 FROM_HERE, | |
188 base::Bind(base::IgnoreResult(&AudioPlayer::IsPlaying), | |
189 base::Unretained(this)), | |
190 rl.QuitClosure()); | |
191 rl.Run(); | |
192 } | |
193 | |
194 bool AudioPlayer::IsPlaying() { | |
195 FlushAudioLoop(); | |
196 return is_playing_; | |
197 } | |
198 | |
199 } // namespace copresence | |
OLD | NEW |