Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(552)

Side by Side Diff: media/audio/audio_input_controller.cc

Issue 9956169: Improved timer implementation in AudioInputController (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/audio/audio_input_controller.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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_input_controller.h" 5 #include "media/audio/audio_input_controller.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/threading/thread_restrictions.h" 8 #include "base/threading/thread_restrictions.h"
9 #include "media/base/limits.h" 9 #include "media/base/limits.h"
10 10
11 namespace { 11 namespace {
12 const int kMaxInputChannels = 2; 12 const int kMaxInputChannels = 2;
13 const int kTimerResetInterval = 1; // One second. 13 const int kTimerResetInterval = 1; // One second.
14 } 14 }
15 15
16 namespace media { 16 namespace media {
17 17
18 // static 18 // static
19 AudioInputController::Factory* AudioInputController::factory_ = NULL; 19 AudioInputController::Factory* AudioInputController::factory_ = NULL;
20 20
21 AudioInputController::AudioInputController(EventHandler* handler, 21 AudioInputController::AudioInputController(EventHandler* handler,
22 SyncWriter* sync_writer) 22 SyncWriter* sync_writer)
23 : creator_loop_(base::MessageLoopProxy::current()), 23 : creator_loop_(base::MessageLoopProxy::current()),
24 handler_(handler), 24 handler_(handler),
25 stream_(NULL), 25 stream_(NULL),
26 state_(kEmpty), 26 state_(kEmpty),
27 sync_writer_(sync_writer), 27 sync_writer_(sync_writer),
28 max_volume_(0.0) { 28 max_volume_(0.0),
29 data_is_active_(false) {
29 DCHECK(creator_loop_); 30 DCHECK(creator_loop_);
30 no_data_timer_.reset(new base::DelayTimer<AudioInputController>(FROM_HERE,
31 base::TimeDelta::FromSeconds(kTimerResetInterval),
32 this,
33 &AudioInputController::DoReportNoDataError));
34 } 31 }
35 32
36 AudioInputController::~AudioInputController() { 33 AudioInputController::~AudioInputController() {
37 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); 34 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_);
38 } 35 }
39 36
40 // static 37 // static
41 scoped_refptr<AudioInputController> AudioInputController::Create( 38 scoped_refptr<AudioInputController> AudioInputController::Create(
42 AudioManager* audio_manager, 39 AudioManager* audio_manager,
43 EventHandler* event_handler, 40 EventHandler* event_handler,
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 } 95 }
99 96
100 void AudioInputController::Record() { 97 void AudioInputController::Record() {
101 message_loop_->PostTask(FROM_HERE, base::Bind( 98 message_loop_->PostTask(FROM_HERE, base::Bind(
102 &AudioInputController::DoRecord, this)); 99 &AudioInputController::DoRecord, this));
103 } 100 }
104 101
105 void AudioInputController::Close(const base::Closure& closed_task) { 102 void AudioInputController::Close(const base::Closure& closed_task) {
106 DCHECK(!closed_task.is_null()); 103 DCHECK(!closed_task.is_null());
107 DCHECK(creator_loop_->BelongsToCurrentThread()); 104 DCHECK(creator_loop_->BelongsToCurrentThread());
108 // See crbug.com/119783: Deleting the timer now to avoid disaster if 105
109 // AudioInputController is destructed on a thread other than the creator
110 // thread.
111 no_data_timer_.reset();
112 message_loop_->PostTaskAndReply( 106 message_loop_->PostTaskAndReply(
113 FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task); 107 FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task);
114 } 108 }
115 109
116 void AudioInputController::SetVolume(double volume) { 110 void AudioInputController::SetVolume(double volume) {
117 message_loop_->PostTask(FROM_HERE, base::Bind( 111 message_loop_->PostTask(FROM_HERE, base::Bind(
118 &AudioInputController::DoSetVolume, this, volume)); 112 &AudioInputController::DoSetVolume, this, volume));
119 } 113 }
120 114
121 void AudioInputController::SetAutomaticGainControl(bool enabled) { 115 void AudioInputController::SetAutomaticGainControl(bool enabled) {
(...skipping 15 matching lines...) Expand all
137 } 131 }
138 132
139 if (stream_ && !stream_->Open()) { 133 if (stream_ && !stream_->Open()) {
140 stream_->Close(); 134 stream_->Close();
141 stream_ = NULL; 135 stream_ = NULL;
142 // TODO(satish): Define error types. 136 // TODO(satish): Define error types.
143 handler_->OnError(this, 0); 137 handler_->OnError(this, 0);
144 return; 138 return;
145 } 139 }
146 140
147 creator_loop_->PostTask(FROM_HERE, base::Bind( 141 // Create the data timer which will call DoCheckForNoData() after a delay
148 &AudioInputController::DoResetNoDataTimer, this)); 142 // of |kTimerResetInterval| seconds. The timer is started in DoRecord()
143 // and restarted in each DoCheckForNoData() callback.
144 no_data_timer_.reset(new base::DelayTimer<AudioInputController>(FROM_HERE,
tommi (sloooow) - chröme 2012/04/17 11:58:31 should we first that no_data_timer_ is NULL?
no longer working on chromium 2012/04/17 12:20:41 can we move these code to DoRecord instead, since
henrika (OOO until Aug 14) 2012/04/17 13:03:27 Done.
henrika (OOO until Aug 14) 2012/04/17 13:03:27 It is possible but I felt it was more symmetric to
145 base::TimeDelta::FromSeconds(kTimerResetInterval),
146 this,
147 &AudioInputController::DoCheckForNoData));
149 148
150 state_ = kCreated; 149 state_ = kCreated;
151 handler_->OnCreated(this); 150 handler_->OnCreated(this);
152 } 151 }
153 152
154 void AudioInputController::DoRecord() { 153 void AudioInputController::DoRecord() {
155 DCHECK(message_loop_->BelongsToCurrentThread()); 154 DCHECK(message_loop_->BelongsToCurrentThread());
156 155
157 if (state_ != kCreated) 156 if (state_ != kCreated)
158 return; 157 return;
159 158
160 { 159 {
161 base::AutoLock auto_lock(lock_); 160 base::AutoLock auto_lock(lock_);
162 state_ = kRecording; 161 state_ = kRecording;
163 } 162 }
164 163
164 // Start the data timer. Once |kTimerResetInterval| seconds have passed,
165 // a callback to DoCheckForNoData() made.
166 DoResetNoDataTimer();
no longer working on chromium 2012/04/17 12:20:41 We can skip this call if we move the code here: no
henrika (OOO until Aug 14) 2012/04/17 13:03:27 Actually no since start requires: create + reset.
167
165 stream_->Start(this); 168 stream_->Start(this);
166 handler_->OnRecording(this); 169 handler_->OnRecording(this);
167 } 170 }
168 171
169 void AudioInputController::DoClose() { 172 void AudioInputController::DoClose() {
170 DCHECK(message_loop_->BelongsToCurrentThread()); 173 DCHECK(message_loop_->BelongsToCurrentThread());
171 174
175 if (no_data_timer_.get()) {
no longer working on chromium 2012/04/17 12:20:41 maybe we can skip the check, and set it regardless
henrika (OOO until Aug 14) 2012/04/17 13:03:27 Not sure why you don't like the non-NULL check. Ca
tommi (sloooow) - chröme 2012/04/17 13:12:49 There is already a NULL check inside reset(), so w
henrika (OOO until Aug 14) 2012/04/17 13:38:31 Done.
176 // Delete the timer on the same thread that created it.
177 no_data_timer_.reset();
178 }
179
172 if (state_ != kClosed) { 180 if (state_ != kClosed) {
173 DoStopCloseAndClearStream(NULL); 181 DoStopCloseAndClearStream(NULL);
182 SetDataIsActive(false);
174 183
175 if (LowLatencyMode()) { 184 if (LowLatencyMode()) {
176 sync_writer_->Close(); 185 sync_writer_->Close();
177 } 186 }
178 187
179 state_ = kClosed; 188 state_ = kClosed;
180 } 189 }
181 } 190 }
182 191
183 void AudioInputController::DoReportError(int code) { 192 void AudioInputController::DoReportError(int code) {
(...skipping 28 matching lines...) Expand all
212 DCHECK(message_loop_->BelongsToCurrentThread()); 221 DCHECK(message_loop_->BelongsToCurrentThread());
213 DCHECK_NE(state_, kRecording); 222 DCHECK_NE(state_, kRecording);
214 223
215 // Ensure that the AGC state only can be modified before streaming starts. 224 // Ensure that the AGC state only can be modified before streaming starts.
216 if (state_ != kCreated || state_ == kRecording) 225 if (state_ != kCreated || state_ == kRecording)
217 return; 226 return;
218 227
219 stream_->SetAutomaticGainControl(enabled); 228 stream_->SetAutomaticGainControl(enabled);
220 } 229 }
221 230
222 void AudioInputController::DoReportNoDataError() { 231 void AudioInputController::DoCheckForNoData() {
223 DCHECK(creator_loop_->BelongsToCurrentThread()); 232 DCHECK(message_loop_->BelongsToCurrentThread());
224 233
225 // Error notifications should be sent on the audio-manager thread. 234 if (!GetDataIsActive()) {
226 int code = 0; 235 // The data-is-active marker will be false only if it has been more than
227 message_loop_->PostTask(FROM_HERE, base::Bind( 236 // one second since a data packet was recorded. This can happen if a
228 &AudioInputController::DoReportError, this, code)); 237 // capture device has been removed or disabled.
238 handler_->OnError(this, 0);
no longer working on chromium 2012/04/17 12:20:41 Shall we delete the timer here?
henrika (OOO until Aug 14) 2012/04/17 13:03:27 No. You must call Close() to delete it. That is do
239 return;
240 }
241
242 // Mark data as non-active. The flag will be re-enabled in OnData() each
243 // time a data packet is received. Hence, under normal conditions, the
244 // flag will only be disabled during a very short period.
245 SetDataIsActive(false);
246
247 // Restart the timer to ensure that we check the flag in one second again.
248 DoResetNoDataTimer();
no longer working on chromium 2012/04/17 12:20:41 can we just called no_data_timer_->Reset() here, a
henrika (OOO until Aug 14) 2012/04/17 13:03:27 Done.
229 } 249 }
230 250
231 void AudioInputController::DoResetNoDataTimer() { 251 void AudioInputController::DoResetNoDataTimer() {
tommi (sloooow) - chröme 2012/04/17 11:58:31 Can we just remove this method and call no_data_ti
henrika (OOO until Aug 14) 2012/04/17 13:03:27 Done.
232 DCHECK(creator_loop_->BelongsToCurrentThread()); 252 DCHECK(message_loop_->BelongsToCurrentThread());
233 if (no_data_timer_.get()) 253 if (no_data_timer_.get())
234 no_data_timer_->Reset(); 254 no_data_timer_->Reset();
235 } 255 }
236 256
237 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data, 257 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data,
238 uint32 size, uint32 hardware_delay_bytes, 258 uint32 size, uint32 hardware_delay_bytes,
239 double volume) { 259 double volume) {
240 { 260 {
241 base::AutoLock auto_lock(lock_); 261 base::AutoLock auto_lock(lock_);
242 if (state_ != kRecording) 262 if (state_ != kRecording)
243 return; 263 return;
244 } 264 }
245 265
246 creator_loop_->PostTask(FROM_HERE, base::Bind( 266 // Mark data as active to ensure that the periodic calls to
247 &AudioInputController::DoResetNoDataTimer, this)); 267 // DoCheckForNoData() does not report an error to the event handler.
268 SetDataIsActive(true);
248 269
249 // Use SyncSocket if we are in a low-latency mode. 270 // Use SyncSocket if we are in a low-latency mode.
250 if (LowLatencyMode()) { 271 if (LowLatencyMode()) {
251 sync_writer_->Write(data, size, volume); 272 sync_writer_->Write(data, size, volume);
252 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); 273 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
253 return; 274 return;
254 } 275 }
255 276
256 handler_->OnData(this, data, size); 277 handler_->OnData(this, data, size);
257 } 278 }
(...skipping 20 matching lines...) Expand all
278 stream_->Stop(); 299 stream_->Stop();
279 stream_->Close(); 300 stream_->Close();
280 stream_ = NULL; 301 stream_ = NULL;
281 } 302 }
282 303
283 // Should be last in the method, do not touch "this" from here on. 304 // Should be last in the method, do not touch "this" from here on.
284 if (done != NULL) 305 if (done != NULL)
285 done->Signal(); 306 done->Signal();
286 } 307 }
287 308
309 void AudioInputController::SetDataIsActive(bool enabled) {
310 base::subtle::Release_Store(&data_is_active_, enabled);
311 }
312
313 bool AudioInputController::GetDataIsActive() {
314 return (base::subtle::Acquire_Load(&data_is_active_) == 1);
tommi (sloooow) - chröme 2012/04/17 11:58:31 nit: Since in the Set method you use bool, check a
henrika (OOO until Aug 14) 2012/04/17 13:03:27 Done.
315 }
316
288 } // namespace media 317 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_input_controller.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698