This source file includes following definitions.
- prev_key_down_count_
- Create
- CreateLowLatency
- CreateForStream
- Record
- Close
- SetVolume
- SetAutomaticGainControl
- DoCreate
- DoCreateForStream
- DoRecord
- DoClose
- DoReportError
- DoSetVolume
- DoSetAutomaticGainControl
- DoCheckForNoData
- OnData
- OnError
- DoStopCloseAndClearStream
- SetDataIsActive
- GetDataIsActive
#include "media/audio/audio_input_controller.h"
#include "base/bind.h"
#include "base/threading/thread_restrictions.h"
#include "media/base/limits.h"
#include "media/base/scoped_histogram_timer.h"
#include "media/base/user_input_monitor.h"
namespace {
const int kMaxInputChannels = 2;
const int kTimerResetIntervalSeconds = 1;
const int kTimerInitialIntervalSeconds = 5;
}
namespace media {
AudioInputController::Factory* AudioInputController::factory_ = NULL;
AudioInputController::AudioInputController(EventHandler* handler,
                                           SyncWriter* sync_writer,
                                           UserInputMonitor* user_input_monitor)
    : creator_task_runner_(base::MessageLoopProxy::current()),
      handler_(handler),
      stream_(NULL),
      data_is_active_(false),
      state_(CLOSED),
      sync_writer_(sync_writer),
      max_volume_(0.0),
      user_input_monitor_(user_input_monitor),
      prev_key_down_count_(0) {
  DCHECK(creator_task_runner_.get());
}
AudioInputController::~AudioInputController() {
  DCHECK_EQ(state_, CLOSED);
}
scoped_refptr<AudioInputController> AudioInputController::Create(
    AudioManager* audio_manager,
    EventHandler* event_handler,
    const AudioParameters& params,
    const std::string& device_id,
    UserInputMonitor* user_input_monitor) {
  DCHECK(audio_manager);
  if (!params.IsValid() || (params.channels() > kMaxInputChannels))
    return NULL;
  if (factory_) {
    return factory_->Create(
        audio_manager, event_handler, params, user_input_monitor);
  }
  scoped_refptr<AudioInputController> controller(
      new AudioInputController(event_handler, NULL, user_input_monitor));
  controller->task_runner_ = audio_manager->GetTaskRunner();
  
  
  if (!controller->task_runner_->PostTask(FROM_HERE,
          base::Bind(&AudioInputController::DoCreate, controller,
                     base::Unretained(audio_manager), params, device_id))) {
    controller = NULL;
  }
  return controller;
}
scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
    AudioManager* audio_manager,
    EventHandler* event_handler,
    const AudioParameters& params,
    const std::string& device_id,
    SyncWriter* sync_writer,
    UserInputMonitor* user_input_monitor) {
  DCHECK(audio_manager);
  DCHECK(sync_writer);
  if (!params.IsValid() || (params.channels() > kMaxInputChannels))
    return NULL;
  
  
  scoped_refptr<AudioInputController> controller(
      new AudioInputController(event_handler, sync_writer, user_input_monitor));
  controller->task_runner_ = audio_manager->GetTaskRunner();
  
  
  if (!controller->task_runner_->PostTask(FROM_HERE,
          base::Bind(&AudioInputController::DoCreate, controller,
                     base::Unretained(audio_manager), params, device_id))) {
    controller = NULL;
  }
  return controller;
}
scoped_refptr<AudioInputController> AudioInputController::CreateForStream(
    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
    EventHandler* event_handler,
    AudioInputStream* stream,
    SyncWriter* sync_writer,
    UserInputMonitor* user_input_monitor) {
  DCHECK(sync_writer);
  DCHECK(stream);
  
  
  scoped_refptr<AudioInputController> controller(
      new AudioInputController(event_handler, sync_writer, user_input_monitor));
  controller->task_runner_ = task_runner;
  
  
  
  
  
  if (!controller->task_runner_->PostTask(
          FROM_HERE,
          base::Bind(&AudioInputController::DoCreateForStream, controller,
                     stream, false))) {
    controller = NULL;
  }
  return controller;
}
void AudioInputController::Record() {
  task_runner_->PostTask(FROM_HERE, base::Bind(
      &AudioInputController::DoRecord, this));
}
void AudioInputController::Close(const base::Closure& closed_task) {
  DCHECK(!closed_task.is_null());
  DCHECK(creator_task_runner_->BelongsToCurrentThread());
  task_runner_->PostTaskAndReply(
      FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task);
}
void AudioInputController::SetVolume(double volume) {
  task_runner_->PostTask(FROM_HERE, base::Bind(
      &AudioInputController::DoSetVolume, this, volume));
}
void AudioInputController::SetAutomaticGainControl(bool enabled) {
  task_runner_->PostTask(FROM_HERE, base::Bind(
      &AudioInputController::DoSetAutomaticGainControl, this, enabled));
}
void AudioInputController::DoCreate(AudioManager* audio_manager,
                                    const AudioParameters& params,
                                    const std::string& device_id) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
  
  
  
  
  DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id),
                    true);
}
void AudioInputController::DoCreateForStream(
    AudioInputStream* stream_to_control, bool enable_nodata_timer) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  DCHECK(!stream_);
  stream_ = stream_to_control;
  if (!stream_) {
    handler_->OnError(this, STREAM_CREATE_ERROR);
    return;
  }
  if (stream_ && !stream_->Open()) {
    stream_->Close();
    stream_ = NULL;
    handler_->OnError(this, STREAM_OPEN_ERROR);
    return;
  }
  DCHECK(!no_data_timer_.get());
  
  
  
  
  
  
  
  
  enable_nodata_timer = false;
  if (enable_nodata_timer) {
    
    
    
    no_data_timer_.reset(new base::Timer(
        FROM_HERE, base::TimeDelta::FromSeconds(kTimerInitialIntervalSeconds),
        base::Bind(&AudioInputController::DoCheckForNoData,
                   base::Unretained(this)), false));
  } else {
    DVLOG(1) << "Disabled: timer check for no data.";
  }
  state_ = CREATED;
  handler_->OnCreated(this);
  if (user_input_monitor_) {
    user_input_monitor_->EnableKeyPressMonitoring();
    prev_key_down_count_ = user_input_monitor_->GetKeyPressCount();
  }
}
void AudioInputController::DoRecord() {
  DCHECK(task_runner_->BelongsToCurrentThread());
  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime");
  if (state_ != CREATED)
    return;
  {
    base::AutoLock auto_lock(lock_);
    state_ = RECORDING;
  }
  if (no_data_timer_) {
    
    
    no_data_timer_->Reset();
  }
  stream_->Start(this);
  handler_->OnRecording(this);
}
void AudioInputController::DoClose() {
  DCHECK(task_runner_->BelongsToCurrentThread());
  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime");
  if (state_ == CLOSED)
    return;
  
  no_data_timer_.reset();
  DoStopCloseAndClearStream(NULL);
  SetDataIsActive(false);
  if (LowLatencyMode())
    sync_writer_->Close();
  if (user_input_monitor_)
    user_input_monitor_->DisableKeyPressMonitoring();
  state_ = CLOSED;
}
void AudioInputController::DoReportError() {
  DCHECK(task_runner_->BelongsToCurrentThread());
  handler_->OnError(this, STREAM_ERROR);
}
void AudioInputController::DoSetVolume(double volume) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  DCHECK_GE(volume, 0);
  DCHECK_LE(volume, 1.0);
  if (state_ != CREATED && state_ != RECORDING)
    return;
  
  
  if (!max_volume_) {
    max_volume_ = stream_->GetMaxVolume();
  }
  if (max_volume_ == 0.0) {
    DLOG(WARNING) << "Failed to access input volume control";
    return;
  }
  
  stream_->SetVolume(max_volume_ * volume);
}
void AudioInputController::DoSetAutomaticGainControl(bool enabled) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  DCHECK_NE(state_, RECORDING);
  
  if (state_ != CREATED)
    return;
  stream_->SetAutomaticGainControl(enabled);
}
void AudioInputController::DoCheckForNoData() {
  DCHECK(task_runner_->BelongsToCurrentThread());
  if (!GetDataIsActive()) {
    
    
    
    handler_->OnError(this, NO_DATA_ERROR);
    return;
  }
  
  
  
  SetDataIsActive(false);
  
  
  no_data_timer_->Start(
      FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds),
      base::Bind(&AudioInputController::DoCheckForNoData,
      base::Unretained(this)));
}
void AudioInputController::OnData(AudioInputStream* stream,
                                  const uint8* data,
                                  uint32 size,
                                  uint32 hardware_delay_bytes,
                                  double volume) {
  {
    base::AutoLock auto_lock(lock_);
    if (state_ != RECORDING)
      return;
  }
  bool key_pressed = false;
  if (user_input_monitor_) {
    size_t current_count = user_input_monitor_->GetKeyPressCount();
    key_pressed = current_count != prev_key_down_count_;
    prev_key_down_count_ = current_count;
    DVLOG_IF(6, key_pressed) << "Detected keypress.";
  }
  
  
  SetDataIsActive(true);
  
  if (LowLatencyMode()) {
    sync_writer_->Write(data, size, volume, key_pressed);
    sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
    return;
  }
  handler_->OnData(this, data, size);
}
void AudioInputController::OnError(AudioInputStream* stream) {
  
  task_runner_->PostTask(FROM_HERE, base::Bind(
      &AudioInputController::DoReportError, this));
}
void AudioInputController::DoStopCloseAndClearStream(
    base::WaitableEvent* done) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  
  if (stream_ != NULL) {
    stream_->Stop();
    stream_->Close();
    stream_ = NULL;
  }
  
  if (done != NULL)
    done->Signal();
}
void AudioInputController::SetDataIsActive(bool enabled) {
  base::subtle::Release_Store(&data_is_active_, enabled);
}
bool AudioInputController::GetDataIsActive() {
  return (base::subtle::Acquire_Load(&data_is_active_) != false);
}
}