OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/audio/audio_output_controller.h" | 5 #include "media/audio/audio_output_controller.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <limits> | 10 #include <limits> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
14 #include "base/numerics/safe_conversions.h" | 14 #include "base/numerics/safe_conversions.h" |
15 #include "base/task_runner_util.h" | 15 #include "base/task_runner_util.h" |
16 #include "base/threading/platform_thread.h" | 16 #include "base/threading/platform_thread.h" |
17 #include "base/time/time.h" | 17 #include "base/time/time.h" |
18 #include "base/trace_event/trace_event.h" | 18 #include "base/trace_event/trace_event.h" |
19 | 19 |
20 using base::TimeDelta; | 20 using base::TimeDelta; |
21 | 21 |
22 namespace media { | 22 namespace media { |
23 | 23 |
24 AudioOutputController::AudioOutputController( | 24 AudioOutputController::AudioOutputController( |
25 AudioManager* audio_manager, | 25 AudioManager* audio_manager, |
26 EventHandler* handler, | 26 EventHandler* handler, |
27 const AudioParameters& params, | 27 const AudioParameters& params, |
28 const std::string& output_device_id, | 28 const std::string& output_device_id, |
29 SyncReader* sync_reader) | 29 std::unique_ptr<SyncReader> sync_reader) |
30 : audio_manager_(audio_manager), | 30 : audio_manager_(audio_manager), |
31 params_(params), | 31 params_(params), |
32 handler_(handler), | 32 handler_(handler), |
33 output_device_id_(output_device_id), | 33 output_device_id_(output_device_id), |
34 stream_(NULL), | 34 stream_(NULL), |
35 diverting_to_stream_(NULL), | 35 diverting_to_stream_(NULL), |
36 volume_(1.0), | 36 volume_(1.0), |
37 state_(kEmpty), | 37 state_(kEmpty), |
38 sync_reader_(sync_reader), | 38 sync_reader_(std::move(sync_reader)), |
39 message_loop_(audio_manager->GetTaskRunner()), | 39 message_loop_(audio_manager->GetTaskRunner()), |
40 power_monitor_( | 40 power_monitor_( |
41 params.sample_rate(), | 41 params.sample_rate(), |
42 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)), | 42 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)), |
43 on_more_io_data_called_(0), | 43 on_more_io_data_called_(0), |
44 ignore_errors_during_stop_close_(false) { | 44 ignore_errors_during_stop_close_(false) { |
45 DCHECK(audio_manager); | 45 DCHECK(audio_manager); |
46 DCHECK(handler_); | 46 DCHECK(handler_); |
47 DCHECK(sync_reader_); | 47 DCHECK(sync_reader_); |
48 DCHECK(message_loop_.get()); | 48 DCHECK(message_loop_.get()); |
49 } | 49 } |
50 | 50 |
51 AudioOutputController::~AudioOutputController() { | 51 AudioOutputController::~AudioOutputController() { |
52 CHECK_EQ(kClosed, state_); | 52 CHECK_EQ(kClosed, state_); |
53 CHECK_EQ(nullptr, stream_); | 53 CHECK_EQ(nullptr, stream_); |
54 CHECK(duplication_targets_.empty()); | 54 CHECK(duplication_targets_.empty()); |
55 } | 55 } |
56 | 56 |
57 // static | 57 // static |
58 scoped_refptr<AudioOutputController> AudioOutputController::Create( | 58 scoped_refptr<AudioOutputController> AudioOutputController::Create( |
59 AudioManager* audio_manager, | 59 AudioManager* audio_manager, |
60 EventHandler* event_handler, | 60 EventHandler* event_handler, |
61 const AudioParameters& params, | 61 const AudioParameters& params, |
62 const std::string& output_device_id, | 62 const std::string& output_device_id, |
63 SyncReader* sync_reader) { | 63 std::unique_ptr<SyncReader> sync_reader) { |
64 CHECK(audio_manager); | 64 CHECK(audio_manager); |
65 CHECK_EQ(AudioManager::Get(), audio_manager); | 65 CHECK_EQ(AudioManager::Get(), audio_manager); |
66 DCHECK(sync_reader); | 66 DCHECK(sync_reader); |
67 | 67 |
68 if (!params.IsValid()) | 68 if (!params.IsValid()) |
69 return NULL; | 69 return NULL; |
70 | 70 |
71 scoped_refptr<AudioOutputController> controller(new AudioOutputController( | 71 scoped_refptr<AudioOutputController> controller( |
72 audio_manager, event_handler, params, output_device_id, sync_reader)); | 72 new AudioOutputController(audio_manager, event_handler, params, |
| 73 output_device_id, std::move(sync_reader))); |
73 controller->message_loop_->PostTask(FROM_HERE, base::Bind( | 74 controller->message_loop_->PostTask(FROM_HERE, base::Bind( |
74 &AudioOutputController::DoCreate, controller, false)); | 75 &AudioOutputController::DoCreate, controller, false)); |
75 return controller; | 76 return controller; |
76 } | 77 } |
77 | 78 |
78 void AudioOutputController::Play() { | 79 void AudioOutputController::Play() { |
79 CHECK_EQ(AudioManager::Get(), audio_manager_); | 80 CHECK_EQ(AudioManager::Get(), audio_manager_); |
80 message_loop_->PostTask(FROM_HERE, base::Bind( | 81 message_loop_->PostTask(FROM_HERE, base::Bind( |
81 &AudioOutputController::DoPlay, this)); | 82 &AudioOutputController::DoPlay, this)); |
82 } | 83 } |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 return; | 131 return; |
131 | 132 |
132 DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener(). | 133 DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener(). |
133 DCHECK_EQ(kEmpty, state_); | 134 DCHECK_EQ(kEmpty, state_); |
134 | 135 |
135 stream_ = diverting_to_stream_ ? | 136 stream_ = diverting_to_stream_ ? |
136 diverting_to_stream_ : | 137 diverting_to_stream_ : |
137 audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_); | 138 audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_); |
138 if (!stream_) { | 139 if (!stream_) { |
139 state_ = kError; | 140 state_ = kError; |
140 handler_->OnError(); | 141 handler_->OnControllerError(); |
141 return; | 142 return; |
142 } | 143 } |
143 | 144 |
144 if (!stream_->Open()) { | 145 if (!stream_->Open()) { |
145 DoStopCloseAndClearStream(); | 146 DoStopCloseAndClearStream(); |
146 state_ = kError; | 147 state_ = kError; |
147 handler_->OnError(); | 148 handler_->OnControllerError(); |
148 return; | 149 return; |
149 } | 150 } |
150 | 151 |
151 // Everything started okay, so re-register for state change callbacks if | 152 // Everything started okay, so re-register for state change callbacks if |
152 // stream_ was created via AudioManager. | 153 // stream_ was created via AudioManager. |
153 if (stream_ != diverting_to_stream_) | 154 if (stream_ != diverting_to_stream_) |
154 audio_manager_->AddOutputDeviceChangeListener(this); | 155 audio_manager_->AddOutputDeviceChangeListener(this); |
155 | 156 |
156 // We have successfully opened the stream. Set the initial volume. | 157 // We have successfully opened the stream. Set the initial volume. |
157 stream_->SetVolume(volume_); | 158 stream_->SetVolume(volume_); |
158 | 159 |
159 // Finally set the state to kCreated. | 160 // Finally set the state to kCreated. |
160 state_ = kCreated; | 161 state_ = kCreated; |
161 | 162 |
162 // And then report we have been created if we haven't done so already. | 163 // And then report we have been created if we haven't done so already. |
163 if (!is_for_device_change) | 164 if (!is_for_device_change) |
164 handler_->OnCreated(); | 165 handler_->OnControllerCreated(); |
165 } | 166 } |
166 | 167 |
167 void AudioOutputController::DoPlay() { | 168 void AudioOutputController::DoPlay() { |
168 DCHECK(message_loop_->BelongsToCurrentThread()); | 169 DCHECK(message_loop_->BelongsToCurrentThread()); |
169 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime"); | 170 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime"); |
170 TRACE_EVENT0("audio", "AudioOutputController::DoPlay"); | 171 TRACE_EVENT0("audio", "AudioOutputController::DoPlay"); |
171 | 172 |
172 // We can start from created or paused state. | 173 // We can start from created or paused state. |
173 if (state_ != kCreated && state_ != kPaused) | 174 if (state_ != kCreated && state_ != kPaused) |
174 return; | 175 return; |
(...skipping 14 matching lines...) Expand all Loading... |
189 // it. | 190 // it. |
190 // | 191 // |
191 // Timer self-manages its lifetime and WedgeCheck() will only record the UMA | 192 // Timer self-manages its lifetime and WedgeCheck() will only record the UMA |
192 // statistic if state is still kPlaying. Additional Start() calls will | 193 // statistic if state is still kPlaying. Additional Start() calls will |
193 // invalidate the previous timer. | 194 // invalidate the previous timer. |
194 wedge_timer_.reset(new base::OneShotTimer()); | 195 wedge_timer_.reset(new base::OneShotTimer()); |
195 wedge_timer_->Start( | 196 wedge_timer_->Start( |
196 FROM_HERE, TimeDelta::FromSeconds(5), this, | 197 FROM_HERE, TimeDelta::FromSeconds(5), this, |
197 &AudioOutputController::WedgeCheck); | 198 &AudioOutputController::WedgeCheck); |
198 | 199 |
199 handler_->OnPlaying(); | 200 handler_->OnControllerPlaying(); |
200 } | 201 } |
201 | 202 |
202 void AudioOutputController::StopStream() { | 203 void AudioOutputController::StopStream() { |
203 DCHECK(message_loop_->BelongsToCurrentThread()); | 204 DCHECK(message_loop_->BelongsToCurrentThread()); |
204 | 205 |
205 if (state_ == kPlaying) { | 206 if (state_ == kPlaying) { |
206 wedge_timer_.reset(); | 207 wedge_timer_.reset(); |
207 stream_->Stop(); | 208 stream_->Stop(); |
208 | 209 |
209 // A stopped stream is silent, and power_montior_.Scan() is no longer being | 210 // A stopped stream is silent, and power_montior_.Scan() is no longer being |
(...skipping 12 matching lines...) Expand all Loading... |
222 StopStream(); | 223 StopStream(); |
223 | 224 |
224 if (state_ != kPaused) | 225 if (state_ != kPaused) |
225 return; | 226 return; |
226 | 227 |
227 // Let the renderer know we've stopped. Necessary to let PPAPI clients know | 228 // Let the renderer know we've stopped. Necessary to let PPAPI clients know |
228 // audio has been shutdown. TODO(dalecurtis): This stinks. PPAPI should have | 229 // audio has been shutdown. TODO(dalecurtis): This stinks. PPAPI should have |
229 // a better way to know when it should exit PPB_Audio_Shared::Run(). | 230 // a better way to know when it should exit PPB_Audio_Shared::Run(). |
230 sync_reader_->UpdatePendingBytes(std::numeric_limits<uint32_t>::max(), 0); | 231 sync_reader_->UpdatePendingBytes(std::numeric_limits<uint32_t>::max(), 0); |
231 | 232 |
232 handler_->OnPaused(); | 233 handler_->OnControllerPaused(); |
233 } | 234 } |
234 | 235 |
235 void AudioOutputController::DoClose() { | 236 void AudioOutputController::DoClose() { |
236 DCHECK(message_loop_->BelongsToCurrentThread()); | 237 DCHECK(message_loop_->BelongsToCurrentThread()); |
237 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime"); | 238 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime"); |
238 TRACE_EVENT0("audio", "AudioOutputController::DoClose"); | 239 TRACE_EVENT0("audio", "AudioOutputController::DoClose"); |
239 | 240 |
240 if (state_ != kClosed) { | 241 if (state_ != kClosed) { |
241 DoStopCloseAndClearStream(); | 242 DoStopCloseAndClearStream(); |
242 sync_reader_->Close(); | 243 sync_reader_->Close(); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 // since it would break the diverted setup. Once diversion is | 284 // since it would break the diverted setup. Once diversion is |
284 // finished using StopDiverting() the output will switch to the new | 285 // finished using StopDiverting() the output will switch to the new |
285 // device ID. | 286 // device ID. |
286 if (stream_ != diverting_to_stream_) | 287 if (stream_ != diverting_to_stream_) |
287 OnDeviceChange(); | 288 OnDeviceChange(); |
288 } | 289 } |
289 | 290 |
290 void AudioOutputController::DoReportError() { | 291 void AudioOutputController::DoReportError() { |
291 DCHECK(message_loop_->BelongsToCurrentThread()); | 292 DCHECK(message_loop_->BelongsToCurrentThread()); |
292 if (state_ != kClosed) | 293 if (state_ != kClosed) |
293 handler_->OnError(); | 294 handler_->OnControllerError(); |
294 } | 295 } |
295 | 296 |
296 int AudioOutputController::OnMoreData(base::TimeDelta delay, | 297 int AudioOutputController::OnMoreData(base::TimeDelta delay, |
297 base::TimeTicks delay_timestamp, | 298 base::TimeTicks delay_timestamp, |
298 int prior_frames_skipped, | 299 int prior_frames_skipped, |
299 AudioBus* dest) { | 300 AudioBus* dest) { |
300 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData"); | 301 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData"); |
301 | 302 |
302 // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck() | 303 // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck() |
303 // may have already fired if OnMoreData() took an abnormal amount of time). | 304 // may have already fired if OnMoreData() took an abnormal amount of time). |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 DCHECK(message_loop_->BelongsToCurrentThread()); | 507 DCHECK(message_loop_->BelongsToCurrentThread()); |
507 | 508 |
508 // If we should be playing and we haven't, that's a wedge. | 509 // If we should be playing and we haven't, that's a wedge. |
509 if (state_ == kPlaying) { | 510 if (state_ == kPlaying) { |
510 UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess", | 511 UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess", |
511 base::AtomicRefCountIsOne(&on_more_io_data_called_)); | 512 base::AtomicRefCountIsOne(&on_more_io_data_called_)); |
512 } | 513 } |
513 } | 514 } |
514 | 515 |
515 } // namespace media | 516 } // namespace media |
OLD | NEW |