OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/threading/platform_thread.h" | 10 #include "base/threading/platform_thread.h" |
11 #include "base/time.h" | 11 #include "base/time.h" |
12 | 12 |
13 using base::Time; | 13 using base::Time; |
14 | 14 |
15 namespace media { | 15 namespace media { |
16 | 16 |
17 // Signal a pause in low-latency mode. | 17 // Signal a pause in low-latency mode. |
18 const int AudioOutputController::kPauseMark = -1; | 18 const int AudioOutputController::kPauseMark = -1; |
19 | 19 |
20 // Polling-related constants. | 20 // Polling-related constants. |
21 const int AudioOutputController::kPollNumAttempts = 3; | 21 const int AudioOutputController::kPollNumAttempts = 3; |
22 const int AudioOutputController::kPollPauseInMilliseconds = 3; | 22 const int AudioOutputController::kPollPauseInMilliseconds = 3; |
23 | 23 |
24 AudioOutputController::AudioOutputController(EventHandler* handler, | 24 AudioOutputController::AudioOutputController(AudioManager* audio_manager, |
| 25 EventHandler* handler, |
25 uint32 capacity, | 26 uint32 capacity, |
26 SyncReader* sync_reader) | 27 SyncReader* sync_reader) |
27 : handler_(handler), | 28 : audio_manager_(audio_manager), |
| 29 handler_(handler), |
28 stream_(NULL), | 30 stream_(NULL), |
29 volume_(1.0), | 31 volume_(1.0), |
30 state_(kEmpty), | 32 state_(kEmpty), |
31 buffer_(0, capacity), | 33 buffer_(0, capacity), |
32 pending_request_(false), | 34 pending_request_(false), |
33 sync_reader_(sync_reader), | 35 sync_reader_(sync_reader), |
34 message_loop_(NULL), | 36 message_loop_(NULL), |
35 number_polling_attempts_left_(0) { | 37 number_polling_attempts_left_(0), |
| 38 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { |
36 } | 39 } |
37 | 40 |
38 AudioOutputController::~AudioOutputController() { | 41 AudioOutputController::~AudioOutputController() { |
39 DCHECK_EQ(kClosed, state_); | 42 DCHECK_EQ(kClosed, state_); |
40 StopCloseAndClearStream(); | 43 StopCloseAndClearStream(); |
41 } | 44 } |
42 | 45 |
43 // static | 46 // static |
44 scoped_refptr<AudioOutputController> AudioOutputController::Create( | 47 scoped_refptr<AudioOutputController> AudioOutputController::Create( |
| 48 AudioManager* audio_manager, |
45 EventHandler* event_handler, | 49 EventHandler* event_handler, |
46 const AudioParameters& params, | 50 const AudioParameters& params, |
47 uint32 buffer_capacity) { | 51 uint32 buffer_capacity) { |
48 | 52 DCHECK(audio_manager); |
49 if (!params.IsValid()) | 53 if (!params.IsValid() || !audio_manager) |
50 return NULL; | |
51 | |
52 if (!AudioManager::GetAudioManager()) | |
53 return NULL; | 54 return NULL; |
54 | 55 |
55 // Starts the audio controller thread. | 56 // Starts the audio controller thread. |
56 scoped_refptr<AudioOutputController> controller(new AudioOutputController( | 57 scoped_refptr<AudioOutputController> controller(new AudioOutputController( |
57 event_handler, buffer_capacity, NULL)); | 58 audio_manager, event_handler, buffer_capacity, NULL)); |
58 | 59 |
59 controller->message_loop_ = | 60 controller->message_loop_ = audio_manager->GetMessageLoop(); |
60 AudioManager::GetAudioManager()->GetMessageLoop(); | |
61 controller->message_loop_->PostTask(FROM_HERE, base::Bind( | 61 controller->message_loop_->PostTask(FROM_HERE, base::Bind( |
62 &AudioOutputController::DoCreate, controller.get(), params)); | 62 &AudioOutputController::DoCreate, base::Unretained(controller.get()), |
| 63 params)); |
63 return controller; | 64 return controller; |
64 } | 65 } |
65 | 66 |
66 // static | 67 // static |
67 scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency( | 68 scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency( |
| 69 AudioManager* audio_manager, |
68 EventHandler* event_handler, | 70 EventHandler* event_handler, |
69 const AudioParameters& params, | 71 const AudioParameters& params, |
70 SyncReader* sync_reader) { | 72 SyncReader* sync_reader) { |
71 | 73 DCHECK(audio_manager); |
72 DCHECK(sync_reader); | 74 DCHECK(sync_reader); |
73 | 75 |
74 if (!params.IsValid()) | 76 if (!params.IsValid() || !audio_manager) |
75 return NULL; | |
76 | |
77 if (!AudioManager::GetAudioManager()) | |
78 return NULL; | 77 return NULL; |
79 | 78 |
80 // Starts the audio controller thread. | 79 // Starts the audio controller thread. |
81 scoped_refptr<AudioOutputController> controller(new AudioOutputController( | 80 scoped_refptr<AudioOutputController> controller(new AudioOutputController( |
82 event_handler, 0, sync_reader)); | 81 audio_manager, event_handler, 0, sync_reader)); |
83 | 82 |
84 controller->message_loop_ = | 83 controller->message_loop_ = audio_manager->GetMessageLoop(); |
85 AudioManager::GetAudioManager()->GetMessageLoop(); | |
86 controller->message_loop_->PostTask(FROM_HERE, base::Bind( | 84 controller->message_loop_->PostTask(FROM_HERE, base::Bind( |
87 &AudioOutputController::DoCreate, controller.get(), params)); | 85 &AudioOutputController::DoCreate, base::Unretained(controller.get()), |
| 86 params)); |
88 return controller; | 87 return controller; |
89 } | 88 } |
90 | 89 |
91 void AudioOutputController::Play() { | 90 void AudioOutputController::Play() { |
92 DCHECK(message_loop_); | 91 DCHECK(message_loop_); |
93 message_loop_->PostTask(FROM_HERE, base::Bind( | 92 message_loop_->PostTask(FROM_HERE, base::Bind( |
94 &AudioOutputController::DoPlay, this)); | 93 &AudioOutputController::DoPlay, base::Unretained(this))); |
95 } | 94 } |
96 | 95 |
97 void AudioOutputController::Pause() { | 96 void AudioOutputController::Pause() { |
98 DCHECK(message_loop_); | 97 DCHECK(message_loop_); |
99 message_loop_->PostTask(FROM_HERE, base::Bind( | 98 message_loop_->PostTask(FROM_HERE, base::Bind( |
100 &AudioOutputController::DoPause, this)); | 99 &AudioOutputController::DoPause, base::Unretained(this))); |
101 } | 100 } |
102 | 101 |
103 void AudioOutputController::Flush() { | 102 void AudioOutputController::Flush() { |
104 DCHECK(message_loop_); | 103 DCHECK(message_loop_); |
105 message_loop_->PostTask(FROM_HERE, base::Bind( | 104 message_loop_->PostTask(FROM_HERE, base::Bind( |
106 &AudioOutputController::DoFlush, this)); | 105 &AudioOutputController::DoFlush, base::Unretained(this))); |
107 } | 106 } |
108 | 107 |
109 void AudioOutputController::Close(const base::Closure& closed_task) { | 108 void AudioOutputController::Close(const base::Closure& closed_task) { |
110 DCHECK(!closed_task.is_null()); | 109 DCHECK(!closed_task.is_null()); |
111 DCHECK(message_loop_); | 110 DCHECK(message_loop_); |
112 message_loop_->PostTask(FROM_HERE, base::Bind( | 111 message_loop_->PostTask(FROM_HERE, base::Bind( |
113 &AudioOutputController::DoClose, this, closed_task)); | 112 &AudioOutputController::DoClose, base::Unretained(this), closed_task)); |
114 } | 113 } |
115 | 114 |
116 void AudioOutputController::SetVolume(double volume) { | 115 void AudioOutputController::SetVolume(double volume) { |
117 DCHECK(message_loop_); | 116 DCHECK(message_loop_); |
118 message_loop_->PostTask(FROM_HERE, base::Bind( | 117 message_loop_->PostTask(FROM_HERE, base::Bind( |
119 &AudioOutputController::DoSetVolume, this, volume)); | 118 &AudioOutputController::DoSetVolume, base::Unretained(this), volume)); |
120 } | 119 } |
121 | 120 |
122 void AudioOutputController::EnqueueData(const uint8* data, uint32 size) { | 121 void AudioOutputController::EnqueueData(const uint8* data, uint32 size) { |
123 // Write data to the push source and ask for more data if needed. | 122 // Write data to the push source and ask for more data if needed. |
124 base::AutoLock auto_lock(lock_); | 123 base::AutoLock auto_lock(lock_); |
125 pending_request_ = false; | 124 pending_request_ = false; |
126 // If |size| is set to 0, it indicates that the audio source doesn't have | 125 // If |size| is set to 0, it indicates that the audio source doesn't have |
127 // more data right now, and so it doesn't make sense to send additional | 126 // more data right now, and so it doesn't make sense to send additional |
128 // request. | 127 // request. |
129 if (size) { | 128 if (size) { |
130 buffer_.Append(data, size); | 129 buffer_.Append(data, size); |
131 SubmitOnMoreData_Locked(); | 130 SubmitOnMoreData_Locked(); |
132 } | 131 } |
133 } | 132 } |
134 | 133 |
135 void AudioOutputController::DoCreate(const AudioParameters& params) { | 134 void AudioOutputController::DoCreate(const AudioParameters& params) { |
136 DCHECK_EQ(message_loop_, MessageLoop::current()); | 135 DCHECK_EQ(message_loop_, MessageLoop::current()); |
137 | 136 |
138 // Close() can be called before DoCreate() is executed. | 137 // Close() can be called before DoCreate() is executed. |
139 if (state_ == kClosed) | 138 if (state_ == kClosed) |
140 return; | 139 return; |
141 DCHECK_EQ(kEmpty, state_); | 140 DCHECK_EQ(kEmpty, state_); |
142 | 141 |
143 if (!AudioManager::GetAudioManager()) | |
144 return; | |
145 | |
146 StopCloseAndClearStream(); | 142 StopCloseAndClearStream(); |
147 stream_ = AudioManager::GetAudioManager()->MakeAudioOutputStreamProxy(params); | 143 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params); |
148 if (!stream_) { | 144 if (!stream_) { |
149 // TODO(hclam): Define error types. | 145 // TODO(hclam): Define error types. |
150 handler_->OnError(this, 0); | 146 handler_->OnError(this, 0); |
151 return; | 147 return; |
152 } | 148 } |
153 | 149 |
154 if (!stream_->Open()) { | 150 if (!stream_->Open()) { |
155 StopCloseAndClearStream(); | 151 StopCloseAndClearStream(); |
156 | 152 |
157 // TODO(hclam): Define error types. | 153 // TODO(hclam): Define error types. |
(...skipping 28 matching lines...) Expand all Loading... |
186 state_ = kStarting; | 182 state_ = kStarting; |
187 | 183 |
188 // Ask for first packet. | 184 // Ask for first packet. |
189 sync_reader_->UpdatePendingBytes(0); | 185 sync_reader_->UpdatePendingBytes(0); |
190 | 186 |
191 // Cannot start stream immediately, should give renderer some time | 187 // Cannot start stream immediately, should give renderer some time |
192 // to deliver data. | 188 // to deliver data. |
193 number_polling_attempts_left_ = kPollNumAttempts; | 189 number_polling_attempts_left_ = kPollNumAttempts; |
194 message_loop_->PostDelayedTask( | 190 message_loop_->PostDelayedTask( |
195 FROM_HERE, | 191 FROM_HERE, |
196 base::Bind(&AudioOutputController::PollAndStartIfDataReady, this), | 192 base::Bind(&AudioOutputController::PollAndStartIfDataReady, |
| 193 weak_this_.GetWeakPtr()), |
197 kPollPauseInMilliseconds); | 194 kPollPauseInMilliseconds); |
198 } else { | 195 } else { |
199 StartStream(); | 196 StartStream(); |
200 } | 197 } |
201 } | 198 } |
202 | 199 |
203 void AudioOutputController::PollAndStartIfDataReady() { | 200 void AudioOutputController::PollAndStartIfDataReady() { |
204 DCHECK_EQ(message_loop_, MessageLoop::current()); | 201 DCHECK_EQ(message_loop_, MessageLoop::current()); |
205 | 202 |
206 // Being paranoic: do nothing if state unexpectedly changed. | 203 // Being paranoid: do nothing if state unexpectedly changed. |
207 if ((state_ != kStarting) && (state_ != kPausedWhenStarting)) | 204 if ((state_ != kStarting) && (state_ != kPausedWhenStarting)) |
208 return; | 205 return; |
209 | 206 |
210 bool pausing = (state_ == kPausedWhenStarting); | 207 bool pausing = (state_ == kPausedWhenStarting); |
211 // If we are ready to start the stream, start it. | 208 // If we are ready to start the stream, start it. |
212 // Of course we may have to stop it immediately... | 209 // Of course we may have to stop it immediately... |
213 if (--number_polling_attempts_left_ == 0 || | 210 if (--number_polling_attempts_left_ == 0 || |
214 pausing || | 211 pausing || |
215 sync_reader_->DataReady()) { | 212 sync_reader_->DataReady()) { |
216 StartStream(); | 213 StartStream(); |
217 if (pausing) { | 214 if (pausing) { |
218 DoPause(); | 215 DoPause(); |
219 } | 216 } |
220 } else { | 217 } else { |
221 message_loop_->PostDelayedTask( | 218 message_loop_->PostDelayedTask( |
222 FROM_HERE, | 219 FROM_HERE, |
223 base::Bind(&AudioOutputController::PollAndStartIfDataReady, this), | 220 base::Bind(&AudioOutputController::PollAndStartIfDataReady, |
| 221 weak_this_.GetWeakPtr()), |
224 kPollPauseInMilliseconds); | 222 kPollPauseInMilliseconds); |
225 } | 223 } |
226 } | 224 } |
227 | 225 |
228 void AudioOutputController::StartStream() { | 226 void AudioOutputController::StartStream() { |
229 DCHECK_EQ(message_loop_, MessageLoop::current()); | 227 DCHECK_EQ(message_loop_, MessageLoop::current()); |
230 state_ = kPlaying; | 228 state_ = kPlaying; |
231 | 229 |
232 // We start the AudioOutputStream lazily. | 230 // We start the AudioOutputStream lazily. |
233 stream_->Start(this); | 231 stream_->Start(this); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 do { | 370 do { |
373 base::PlatformThread::Sleep(1); | 371 base::PlatformThread::Sleep(1); |
374 } while (!sync_reader_->DataReady() && | 372 } while (!sync_reader_->DataReady() && |
375 (Time::Now() - start_time).InMilliseconds() < kMaxPollingDelayMs); | 373 (Time::Now() - start_time).InMilliseconds() < kMaxPollingDelayMs); |
376 } | 374 } |
377 } | 375 } |
378 | 376 |
379 void AudioOutputController::OnError(AudioOutputStream* stream, int code) { | 377 void AudioOutputController::OnError(AudioOutputStream* stream, int code) { |
380 // Handle error on the audio controller thread. | 378 // Handle error on the audio controller thread. |
381 message_loop_->PostTask(FROM_HERE, base::Bind( | 379 message_loop_->PostTask(FROM_HERE, base::Bind( |
382 &AudioOutputController::DoReportError, this, code)); | 380 &AudioOutputController::DoReportError, base::Unretained(this), code)); |
383 } | 381 } |
384 | 382 |
385 void AudioOutputController::SubmitOnMoreData_Locked() { | 383 void AudioOutputController::SubmitOnMoreData_Locked() { |
386 lock_.AssertAcquired(); | 384 lock_.AssertAcquired(); |
387 | 385 |
388 if (buffer_.forward_bytes() > buffer_.forward_capacity()) | 386 if (buffer_.forward_bytes() > buffer_.forward_capacity()) |
389 return; | 387 return; |
390 | 388 |
391 if (pending_request_) | 389 if (pending_request_) |
392 return; | 390 return; |
393 pending_request_ = true; | 391 pending_request_ = true; |
394 | 392 |
395 AudioBuffersState buffers_state = buffers_state_; | 393 AudioBuffersState buffers_state = buffers_state_; |
396 buffers_state.pending_bytes += buffer_.forward_bytes(); | 394 buffers_state.pending_bytes += buffer_.forward_bytes(); |
397 | 395 |
398 // If we need more data then call the event handler to ask for more data. | 396 // If we need more data then call the event handler to ask for more data. |
399 // It is okay that we don't lock in this block because the parameters are | 397 // It is okay that we don't lock in this block because the parameters are |
400 // correct and in the worst case we are just asking more data than needed. | 398 // correct and in the worst case we are just asking more data than needed. |
401 base::AutoUnlock auto_unlock(lock_); | 399 base::AutoUnlock auto_unlock(lock_); |
402 handler_->OnMoreData(this, buffers_state); | 400 handler_->OnMoreData(this, buffers_state); |
403 } | 401 } |
404 | 402 |
405 void AudioOutputController::StopCloseAndClearStream() { | 403 void AudioOutputController::StopCloseAndClearStream() { |
406 // Allow calling unconditionally and bail if we don't have a stream_ to close. | 404 // Allow calling unconditionally and bail if we don't have a stream_ to close. |
407 if (!stream_) | 405 if (!stream_) |
408 return; | 406 return; |
409 stream_->Stop(); | 407 stream_->Stop(); |
410 stream_->Close(); | 408 stream_->Close(); |
411 stream_ = NULL; | 409 stream_ = NULL; |
| 410 weak_this_.InvalidateWeakPtrs(); |
412 } | 411 } |
413 | 412 |
414 } // namespace media | 413 } // namespace media |
OLD | NEW |