blob: fc4b97df67fc61b8d89b5e2d003b5451723e799c [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/audio/audio_input_controller.h"
#include "media/base/limits.h"
namespace {
const int kMaxInputChannels = 2;
const int kMaxSamplesPerPacket = media::Limits::kMaxSampleRate;
} // namespace
namespace media {
// static
AudioInputController::Factory* AudioInputController::factory_ = NULL;
AudioInputController::AudioInputController(EventHandler* handler)
: handler_(handler),
stream_(NULL),
state_(kEmpty),
thread_("AudioInputControllerThread") {
}
AudioInputController::~AudioInputController() {
DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_);
}
// static
scoped_refptr<AudioInputController> AudioInputController::Create(
EventHandler* event_handler,
AudioParameters params,
int samples_per_packet) {
if (!params.IsValid() ||
(params.channels > kMaxInputChannels) ||
(samples_per_packet > kMaxSamplesPerPacket) || (samples_per_packet < 0))
return NULL;
if (factory_) {
return factory_->Create(event_handler, params, samples_per_packet);
}
scoped_refptr<AudioInputController> controller = new AudioInputController(
event_handler);
// Start the thread and post a task to create the audio input stream.
controller->thread_.Start();
controller->thread_.message_loop()->PostTask(
FROM_HERE,
NewRunnableMethod(controller.get(), &AudioInputController::DoCreate,
params, samples_per_packet));
return controller;
}
void AudioInputController::Record() {
DCHECK(thread_.IsRunning());
thread_.message_loop()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &AudioInputController::DoRecord));
}
void AudioInputController::Close() {
if (!thread_.IsRunning()) {
// If the thread is not running make sure we are stopped.
DCHECK_EQ(kClosed, state_);
return;
}
// Wait for all tasks to complete on the audio thread.
thread_.message_loop()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &AudioInputController::DoClose));
thread_.Stop();
}
void AudioInputController::DoCreate(AudioParameters params,
uint32 samples_per_packet) {
stream_ = AudioManager::GetAudioManager()->MakeAudioInputStream(
params, samples_per_packet);
if (!stream_) {
// TODO(satish): Define error types.
handler_->OnError(this, 0);
return;
}
if (stream_ && !stream_->Open()) {
stream_->Close();
stream_ = NULL;
// TODO(satish): Define error types.
handler_->OnError(this, 0);
return;
}
state_ = kCreated;
handler_->OnCreated(this);
}
void AudioInputController::DoRecord() {
DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
if (state_ != kCreated)
return;
{
AutoLock auto_lock(lock_);
state_ = kRecording;
}
stream_->Start(this);
handler_->OnRecording(this);
}
void AudioInputController::DoClose() {
DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
DCHECK_NE(kClosed, state_);
// |stream_| can be null if creating the device failed in DoCreate().
if (stream_) {
stream_->Stop();
stream_->Close();
// After stream is closed it is destroyed, so don't keep a reference to it.
stream_ = NULL;
}
// Since the stream is closed at this point there's no other threads reading
// |state_| so we don't need to lock.
state_ = kClosed;
}
void AudioInputController::DoReportError(int code) {
DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
handler_->OnError(this, code);
}
void AudioInputController::OnData(AudioInputStream* stream, const uint8* data,
uint32 size) {
{
AutoLock auto_lock(lock_);
if (state_ != kRecording)
return;
}
handler_->OnData(this, data, size);
}
void AudioInputController::OnClose(AudioInputStream* stream) {
// TODO(satish): Sometimes the device driver closes the input stream without
// us asking for it (may be if the device was unplugged?). Check how to handle
// such cases here.
}
void AudioInputController::OnError(AudioInputStream* stream, int code) {
// Handle error on the audio controller thread.
thread_.message_loop()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &AudioInputController::DoReportError, code));
}
} // namespace media