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

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