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

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: Changes based on first review round 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 data_is_active_(false),
26 state_(kEmpty), 27 state_(kEmpty),
27 sync_writer_(sync_writer), 28 sync_writer_(sync_writer),
28 max_volume_(0.0) { 29 max_volume_(0.0) {
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 if (!no_data_timer_.get()) {
tommi (sloooow) - chröme 2012/04/17 13:12:49 sorry, what I meant was this: DCHECK(!no_data_tim
henrika (OOO until Aug 14) 2012/04/17 13:38:31 Done.
148 &AudioInputController::DoResetNoDataTimer, this)); 142 // Create the data timer which will call DoCheckForNoData() after a delay
143 // of |kTimerResetInterval| seconds. The timer is started in DoRecord()
144 // and restarted in each DoCheckForNoData() callback.
145 no_data_timer_.reset(new base::DelayTimer<AudioInputController>(FROM_HERE,
146 base::TimeDelta::FromSeconds(kTimerResetInterval),
147 this,
148 &AudioInputController::DoCheckForNoData));
149 }
149 150
150 state_ = kCreated; 151 state_ = kCreated;
151 handler_->OnCreated(this); 152 handler_->OnCreated(this);
152 } 153 }
153 154
154 void AudioInputController::DoRecord() { 155 void AudioInputController::DoRecord() {
155 DCHECK(message_loop_->BelongsToCurrentThread()); 156 DCHECK(message_loop_->BelongsToCurrentThread());
156 157
157 if (state_ != kCreated) 158 if (state_ != kCreated)
158 return; 159 return;
159 160
160 { 161 {
161 base::AutoLock auto_lock(lock_); 162 base::AutoLock auto_lock(lock_);
162 state_ = kRecording; 163 state_ = kRecording;
163 } 164 }
164 165
166 // Start the data timer. Once |kTimerResetInterval| seconds have passed,
167 // a callback to DoCheckForNoData() made.
168 no_data_timer_->Reset();
169
165 stream_->Start(this); 170 stream_->Start(this);
166 handler_->OnRecording(this); 171 handler_->OnRecording(this);
167 } 172 }
168 173
169 void AudioInputController::DoClose() { 174 void AudioInputController::DoClose() {
170 DCHECK(message_loop_->BelongsToCurrentThread()); 175 DCHECK(message_loop_->BelongsToCurrentThread());
171 176
177 if (no_data_timer_.get()) {
178 // Delete the timer on the same thread that created it.
179 no_data_timer_.reset();
180 }
181
172 if (state_ != kClosed) { 182 if (state_ != kClosed) {
173 DoStopCloseAndClearStream(NULL); 183 DoStopCloseAndClearStream(NULL);
184 SetDataIsActive(false);
174 185
175 if (LowLatencyMode()) { 186 if (LowLatencyMode()) {
176 sync_writer_->Close(); 187 sync_writer_->Close();
177 } 188 }
178 189
179 state_ = kClosed; 190 state_ = kClosed;
180 } 191 }
181 } 192 }
182 193
183 void AudioInputController::DoReportError(int code) { 194 void AudioInputController::DoReportError(int code) {
(...skipping 28 matching lines...) Expand all
212 DCHECK(message_loop_->BelongsToCurrentThread()); 223 DCHECK(message_loop_->BelongsToCurrentThread());
213 DCHECK_NE(state_, kRecording); 224 DCHECK_NE(state_, kRecording);
214 225
215 // Ensure that the AGC state only can be modified before streaming starts. 226 // Ensure that the AGC state only can be modified before streaming starts.
216 if (state_ != kCreated || state_ == kRecording) 227 if (state_ != kCreated || state_ == kRecording)
217 return; 228 return;
218 229
219 stream_->SetAutomaticGainControl(enabled); 230 stream_->SetAutomaticGainControl(enabled);
220 } 231 }
221 232
222 void AudioInputController::DoReportNoDataError() { 233 void AudioInputController::DoCheckForNoData() {
223 DCHECK(creator_loop_->BelongsToCurrentThread()); 234 DCHECK(message_loop_->BelongsToCurrentThread());
224 235
225 // Error notifications should be sent on the audio-manager thread. 236 if (!GetDataIsActive()) {
226 int code = 0; 237 // The data-is-active marker will be false only if it has been more than
227 message_loop_->PostTask(FROM_HERE, base::Bind( 238 // one second since a data packet was recorded. This can happen if a
228 &AudioInputController::DoReportError, this, code)); 239 // capture device has been removed or disabled.
229 } 240 handler_->OnError(this, 0);
241 return;
242 }
230 243
231 void AudioInputController::DoResetNoDataTimer() { 244 // Mark data as non-active. The flag will be re-enabled in OnData() each
232 DCHECK(creator_loop_->BelongsToCurrentThread()); 245 // time a data packet is received. Hence, under normal conditions, the
233 if (no_data_timer_.get()) 246 // flag will only be disabled during a very short period.
234 no_data_timer_->Reset(); 247 SetDataIsActive(false);
248
249 // Restart the timer to ensure that we check the flag in one second again.
250 no_data_timer_->Reset();
235 } 251 }
236 252
237 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data, 253 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data,
238 uint32 size, uint32 hardware_delay_bytes, 254 uint32 size, uint32 hardware_delay_bytes,
239 double volume) { 255 double volume) {
240 { 256 {
241 base::AutoLock auto_lock(lock_); 257 base::AutoLock auto_lock(lock_);
242 if (state_ != kRecording) 258 if (state_ != kRecording)
243 return; 259 return;
244 } 260 }
245 261
246 creator_loop_->PostTask(FROM_HERE, base::Bind( 262 // Mark data as active to ensure that the periodic calls to
247 &AudioInputController::DoResetNoDataTimer, this)); 263 // DoCheckForNoData() does not report an error to the event handler.
264 SetDataIsActive(true);
248 265
249 // Use SyncSocket if we are in a low-latency mode. 266 // Use SyncSocket if we are in a low-latency mode.
250 if (LowLatencyMode()) { 267 if (LowLatencyMode()) {
251 sync_writer_->Write(data, size, volume); 268 sync_writer_->Write(data, size, volume);
252 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); 269 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
253 return; 270 return;
254 } 271 }
255 272
256 handler_->OnData(this, data, size); 273 handler_->OnData(this, data, size);
257 } 274 }
(...skipping 20 matching lines...) Expand all
278 stream_->Stop(); 295 stream_->Stop();
279 stream_->Close(); 296 stream_->Close();
280 stream_ = NULL; 297 stream_ = NULL;
281 } 298 }
282 299
283 // Should be last in the method, do not touch "this" from here on. 300 // Should be last in the method, do not touch "this" from here on.
284 if (done != NULL) 301 if (done != NULL)
285 done->Signal(); 302 done->Signal();
286 } 303 }
287 304
305 void AudioInputController::SetDataIsActive(bool enabled) {
306 base::subtle::Release_Store(&data_is_active_, enabled);
307 }
308
309 bool AudioInputController::GetDataIsActive() {
310 return (base::subtle::Acquire_Load(&data_is_active_) != false);
311 }
312
288 } // namespace media 313 } // 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