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
3// found in the LICENSE file.
4
5#include "media/audio/audio_input_controller.h"
6
7#include "base/bind.h"
8#include "base/threading/thread_restrictions.h"
9#include "media/base/limits.h"
10#include "media/base/scoped_histogram_timer.h"
11#include "media/base/user_input_monitor.h"
12
13namespace {
14const int kMaxInputChannels = 2;
15
16// TODO(henrika): remove usage of timers and add support for proper
17// notification of when the input device is removed.  This was originally added
18// to resolve http://crbug.com/79936 for Windows platforms.  This then caused
19// breakage (very hard to repro bugs!) on other platforms: See
20// http://crbug.com/226327 and http://crbug.com/230972.
21const int kTimerResetIntervalSeconds = 1;
22// We have received reports that the timer can be too trigger happy on some
23// Mac devices and the initial timer interval has therefore been increased
24// from 1 second to 5 seconds.
25const int kTimerInitialIntervalSeconds = 5;
26}
27
28namespace media {
29
30// static
31AudioInputController::Factory* AudioInputController::factory_ = NULL;
32
33AudioInputController::AudioInputController(EventHandler* handler,
34                                           SyncWriter* sync_writer,
35                                           UserInputMonitor* user_input_monitor)
36    : creator_loop_(base::MessageLoopProxy::current()),
37      handler_(handler),
38      stream_(NULL),
39      data_is_active_(false),
40      state_(kEmpty),
41      sync_writer_(sync_writer),
42      max_volume_(0.0),
43      user_input_monitor_(user_input_monitor),
44      prev_key_down_count_(0) {
45  DCHECK(creator_loop_.get());
46}
47
48AudioInputController::~AudioInputController() {
49  DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_);
50}
51
52// static
53scoped_refptr<AudioInputController> AudioInputController::Create(
54    AudioManager* audio_manager,
55    EventHandler* event_handler,
56    const AudioParameters& params,
57    const std::string& device_id,
58    UserInputMonitor* user_input_monitor) {
59  DCHECK(audio_manager);
60
61  if (!params.IsValid() || (params.channels() > kMaxInputChannels))
62    return NULL;
63
64  if (factory_) {
65    return factory_->Create(
66        audio_manager, event_handler, params, user_input_monitor);
67  }
68  scoped_refptr<AudioInputController> controller(
69      new AudioInputController(event_handler, NULL, user_input_monitor));
70
71  controller->message_loop_ = audio_manager->GetMessageLoop();
72
73  // Create and open a new audio input stream from the existing
74  // audio-device thread.
75  if (!controller->message_loop_->PostTask(FROM_HERE,
76          base::Bind(&AudioInputController::DoCreate, controller,
77                     base::Unretained(audio_manager), params, device_id))) {
78    controller = NULL;
79  }
80
81  return controller;
82}
83
84// static
85scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
86    AudioManager* audio_manager,
87    EventHandler* event_handler,
88    const AudioParameters& params,
89    const std::string& device_id,
90    SyncWriter* sync_writer,
91    UserInputMonitor* user_input_monitor) {
92  DCHECK(audio_manager);
93  DCHECK(sync_writer);
94
95  if (!params.IsValid() || (params.channels() > kMaxInputChannels))
96    return NULL;
97
98  // Create the AudioInputController object and ensure that it runs on
99  // the audio-manager thread.
100  scoped_refptr<AudioInputController> controller(
101      new AudioInputController(event_handler, sync_writer, user_input_monitor));
102  controller->message_loop_ = audio_manager->GetMessageLoop();
103
104  // Create and open a new audio input stream from the existing
105  // audio-device thread. Use the provided audio-input device.
106  if (!controller->message_loop_->PostTask(FROM_HERE,
107          base::Bind(&AudioInputController::DoCreate, controller,
108                     base::Unretained(audio_manager), params, device_id))) {
109    controller = NULL;
110  }
111
112  return controller;
113}
114
115// static
116scoped_refptr<AudioInputController> AudioInputController::CreateForStream(
117    const scoped_refptr<base::MessageLoopProxy>& message_loop,
118    EventHandler* event_handler,
119    AudioInputStream* stream,
120    SyncWriter* sync_writer,
121    UserInputMonitor* user_input_monitor) {
122  DCHECK(sync_writer);
123  DCHECK(stream);
124
125  // Create the AudioInputController object and ensure that it runs on
126  // the audio-manager thread.
127  scoped_refptr<AudioInputController> controller(
128      new AudioInputController(event_handler, sync_writer, user_input_monitor));
129  controller->message_loop_ = message_loop;
130
131  // TODO(miu): See TODO at top of file.  Until that's resolved, we need to
132  // disable the error auto-detection here (since the audio mirroring
133  // implementation will reliably report error and close events).  Note, of
134  // course, that we're assuming CreateForStream() has been called for the audio
135  // mirroring use case only.
136  if (!controller->message_loop_->PostTask(
137          FROM_HERE,
138          base::Bind(&AudioInputController::DoCreateForStream, controller,
139                     stream, false))) {
140    controller = NULL;
141  }
142
143  return controller;
144}
145
146void AudioInputController::Record() {
147  message_loop_->PostTask(FROM_HERE, base::Bind(
148      &AudioInputController::DoRecord, this));
149}
150
151void AudioInputController::Close(const base::Closure& closed_task) {
152  DCHECK(!closed_task.is_null());
153  DCHECK(creator_loop_->BelongsToCurrentThread());
154
155  message_loop_->PostTaskAndReply(
156      FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task);
157}
158
159void AudioInputController::SetVolume(double volume) {
160  message_loop_->PostTask(FROM_HERE, base::Bind(
161      &AudioInputController::DoSetVolume, this, volume));
162}
163
164void AudioInputController::SetAutomaticGainControl(bool enabled) {
165  message_loop_->PostTask(FROM_HERE, base::Bind(
166      &AudioInputController::DoSetAutomaticGainControl, this, enabled));
167}
168
169void AudioInputController::DoCreate(AudioManager* audio_manager,
170                                    const AudioParameters& params,
171                                    const std::string& device_id) {
172  DCHECK(message_loop_->BelongsToCurrentThread());
173  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
174  // TODO(miu): See TODO at top of file.  Until that's resolved, assume all
175  // platform audio input requires the |no_data_timer_| be used to auto-detect
176  // errors.  In reality, probably only Windows needs to be treated as
177  // unreliable here.
178  DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id),
179                    true);
180}
181
182void AudioInputController::DoCreateForStream(
183    AudioInputStream* stream_to_control, bool enable_nodata_timer) {
184  DCHECK(message_loop_->BelongsToCurrentThread());
185
186  DCHECK(!stream_);
187  stream_ = stream_to_control;
188
189  if (!stream_) {
190    handler_->OnError(this);
191    return;
192  }
193
194  if (stream_ && !stream_->Open()) {
195    stream_->Close();
196    stream_ = NULL;
197    handler_->OnError(this);
198    return;
199  }
200
201  DCHECK(!no_data_timer_.get());
202  if (enable_nodata_timer) {
203    // Create the data timer which will call DoCheckForNoData(). The timer
204    // is started in DoRecord() and restarted in each DoCheckForNoData()
205    // callback.
206    no_data_timer_.reset(new base::Timer(
207        FROM_HERE, base::TimeDelta::FromSeconds(kTimerInitialIntervalSeconds),
208        base::Bind(&AudioInputController::DoCheckForNoData,
209                   base::Unretained(this)), false));
210  } else {
211    DVLOG(1) << "Disabled: timer check for no data.";
212  }
213
214  state_ = kCreated;
215  handler_->OnCreated(this);
216
217  if (user_input_monitor_) {
218    user_input_monitor_->EnableKeyPressMonitoring();
219    prev_key_down_count_ = user_input_monitor_->GetKeyPressCount();
220  }
221}
222
223void AudioInputController::DoRecord() {
224  DCHECK(message_loop_->BelongsToCurrentThread());
225  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime");
226
227  if (state_ != kCreated)
228    return;
229
230  {
231    base::AutoLock auto_lock(lock_);
232    state_ = kRecording;
233  }
234
235  if (no_data_timer_) {
236    // Start the data timer. Once |kTimerResetIntervalSeconds| have passed,
237    // a callback to DoCheckForNoData() is made.
238    no_data_timer_->Reset();
239  }
240
241  stream_->Start(this);
242  handler_->OnRecording(this);
243}
244
245void AudioInputController::DoClose() {
246  DCHECK(message_loop_->BelongsToCurrentThread());
247  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime");
248
249  // Delete the timer on the same thread that created it.
250  no_data_timer_.reset();
251
252  if (state_ != kClosed) {
253    DoStopCloseAndClearStream(NULL);
254    SetDataIsActive(false);
255
256    if (LowLatencyMode()) {
257      sync_writer_->Close();
258    }
259
260    state_ = kClosed;
261
262    if (user_input_monitor_)
263      user_input_monitor_->DisableKeyPressMonitoring();
264  }
265}
266
267void AudioInputController::DoReportError() {
268  DCHECK(message_loop_->BelongsToCurrentThread());
269  handler_->OnError(this);
270}
271
272void AudioInputController::DoSetVolume(double volume) {
273  DCHECK(message_loop_->BelongsToCurrentThread());
274  DCHECK_GE(volume, 0);
275  DCHECK_LE(volume, 1.0);
276
277  if (state_ != kCreated && state_ != kRecording)
278    return;
279
280  // Only ask for the maximum volume at first call and use cached value
281  // for remaining function calls.
282  if (!max_volume_) {
283    max_volume_ = stream_->GetMaxVolume();
284  }
285
286  if (max_volume_ == 0.0) {
287    DLOG(WARNING) << "Failed to access input volume control";
288    return;
289  }
290
291  // Set the stream volume and scale to a range matched to the platform.
292  stream_->SetVolume(max_volume_ * volume);
293}
294
295void AudioInputController::DoSetAutomaticGainControl(bool enabled) {
296  DCHECK(message_loop_->BelongsToCurrentThread());
297  DCHECK_NE(state_, kRecording);
298
299  // Ensure that the AGC state only can be modified before streaming starts.
300  if (state_ != kCreated || state_ == kRecording)
301    return;
302
303  stream_->SetAutomaticGainControl(enabled);
304}
305
306void AudioInputController::DoCheckForNoData() {
307  DCHECK(message_loop_->BelongsToCurrentThread());
308
309  if (!GetDataIsActive()) {
310    // The data-is-active marker will be false only if it has been more than
311    // one second since a data packet was recorded. This can happen if a
312    // capture device has been removed or disabled.
313    handler_->OnError(this);
314    return;
315  }
316
317  // Mark data as non-active. The flag will be re-enabled in OnData() each
318  // time a data packet is received. Hence, under normal conditions, the
319  // flag will only be disabled during a very short period.
320  SetDataIsActive(false);
321
322  // Restart the timer to ensure that we check the flag again in
323  // |kTimerResetIntervalSeconds|.
324  no_data_timer_->Start(
325      FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds),
326      base::Bind(&AudioInputController::DoCheckForNoData,
327      base::Unretained(this)));
328}
329
330void AudioInputController::OnData(AudioInputStream* stream,
331                                  const uint8* data,
332                                  uint32 size,
333                                  uint32 hardware_delay_bytes,
334                                  double volume) {
335  {
336    base::AutoLock auto_lock(lock_);
337    if (state_ != kRecording)
338      return;
339  }
340
341  bool key_pressed = false;
342  if (user_input_monitor_) {
343    size_t current_count = user_input_monitor_->GetKeyPressCount();
344    key_pressed = current_count != prev_key_down_count_;
345    prev_key_down_count_ = current_count;
346    DVLOG_IF(6, key_pressed) << "Detected keypress.";
347  }
348
349  // Mark data as active to ensure that the periodic calls to
350  // DoCheckForNoData() does not report an error to the event handler.
351  SetDataIsActive(true);
352
353  // Use SyncSocket if we are in a low-latency mode.
354  if (LowLatencyMode()) {
355    sync_writer_->Write(data, size, volume, key_pressed);
356    sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
357    return;
358  }
359
360  handler_->OnData(this, data, size);
361}
362
363void AudioInputController::OnClose(AudioInputStream* stream) {
364  DVLOG(1) << "AudioInputController::OnClose()";
365  // TODO(satish): Sometimes the device driver closes the input stream without
366  // us asking for it (may be if the device was unplugged?). Check how to handle
367  // such cases here.
368}
369
370void AudioInputController::OnError(AudioInputStream* stream) {
371  // Handle error on the audio-manager thread.
372  message_loop_->PostTask(FROM_HERE, base::Bind(
373      &AudioInputController::DoReportError, this));
374}
375
376void AudioInputController::DoStopCloseAndClearStream(
377    base::WaitableEvent* done) {
378  DCHECK(message_loop_->BelongsToCurrentThread());
379
380  // Allow calling unconditionally and bail if we don't have a stream to close.
381  if (stream_ != NULL) {
382    stream_->Stop();
383    stream_->Close();
384    stream_ = NULL;
385  }
386
387  // Should be last in the method, do not touch "this" from here on.
388  if (done != NULL)
389    done->Signal();
390}
391
392void AudioInputController::SetDataIsActive(bool enabled) {
393  base::subtle::Release_Store(&data_is_active_, enabled);
394}
395
396bool AudioInputController::GetDataIsActive() {
397  return (base::subtle::Acquire_Load(&data_is_active_) != false);
398}
399
400}  // namespace media
401