This source file includes following definitions.
- stopping_hack_
- Initialize
- Start
- Stop
- SetVolume
- SetAutomaticGainControl
- OnStreamCreated
- OnVolume
- OnStateChanged
- OnIPCClosed
- StartUpOnIOThread
- ShutDownOnIOThread
- SetVolumeOnIOThread
- SetAutomaticGainControlOnIOThread
- WillDestroyCurrentMessageLoop
- capture_callback_
- MapSharedMemory
- Process
#include "media/audio/audio_input_device.h"
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "media/audio/audio_manager_base.h"
#include "media/base/audio_bus.h"
namespace media {
static const int kRequestedSharedMemoryCount = 10;
class AudioInputDevice::AudioThreadCallback
: public AudioDeviceThread::Callback {
public:
AudioThreadCallback(const AudioParameters& audio_parameters,
base::SharedMemoryHandle memory,
int memory_length,
int total_segments,
CaptureCallback* capture_callback);
virtual ~AudioThreadCallback();
virtual void MapSharedMemory() OVERRIDE;
virtual void Process(int pending_data) OVERRIDE;
private:
int current_segment_id_;
CaptureCallback* capture_callback_;
scoped_ptr<AudioBus> audio_bus_;
DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
};
AudioInputDevice::AudioInputDevice(
scoped_ptr<AudioInputIPC> ipc,
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
: ScopedTaskRunnerObserver(io_task_runner),
callback_(NULL),
ipc_(ipc.Pass()),
state_(IDLE),
session_id_(0),
agc_is_enabled_(false),
stopping_hack_(false) {
CHECK(ipc_);
COMPILE_ASSERT(IPC_CLOSED < IDLE, invalid_enum_value_assignment_0);
COMPILE_ASSERT(IDLE < CREATING_STREAM, invalid_enum_value_assignment_1);
COMPILE_ASSERT(CREATING_STREAM < RECORDING, invalid_enum_value_assignment_2);
}
void AudioInputDevice::Initialize(const AudioParameters& params,
CaptureCallback* callback,
int session_id) {
DCHECK(params.IsValid());
DCHECK(!callback_);
DCHECK_EQ(0, session_id_);
audio_parameters_ = params;
callback_ = callback;
session_id_ = session_id;
}
void AudioInputDevice::Start() {
DCHECK(callback_) << "Initialize hasn't been called";
DVLOG(1) << "Start()";
task_runner()->PostTask(FROM_HERE,
base::Bind(&AudioInputDevice::StartUpOnIOThread, this));
}
void AudioInputDevice::Stop() {
DVLOG(1) << "Stop()";
{
base::AutoLock auto_lock(audio_thread_lock_);
audio_thread_.Stop(base::MessageLoop::current());
stopping_hack_ = true;
}
task_runner()->PostTask(FROM_HERE,
base::Bind(&AudioInputDevice::ShutDownOnIOThread, this));
}
void AudioInputDevice::SetVolume(double volume) {
if (volume < 0 || volume > 1.0) {
DLOG(ERROR) << "Invalid volume value specified";
return;
}
task_runner()->PostTask(FROM_HERE,
base::Bind(&AudioInputDevice::SetVolumeOnIOThread, this, volume));
}
void AudioInputDevice::SetAutomaticGainControl(bool enabled) {
DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")";
task_runner()->PostTask(FROM_HERE,
base::Bind(&AudioInputDevice::SetAutomaticGainControlOnIOThread,
this, enabled));
}
void AudioInputDevice::OnStreamCreated(
base::SharedMemoryHandle handle,
base::SyncSocket::Handle socket_handle,
int length,
int total_segments) {
DCHECK(task_runner()->BelongsToCurrentThread());
#if defined(OS_WIN)
DCHECK(handle);
DCHECK(socket_handle);
#else
DCHECK_GE(handle.fd, 0);
DCHECK_GE(socket_handle, 0);
#endif
DCHECK_GT(length, 0);
if (state_ != CREATING_STREAM)
return;
base::AutoLock auto_lock(audio_thread_lock_);
if (stopping_hack_)
return;
DCHECK(audio_thread_.IsStopped());
audio_callback_.reset(new AudioInputDevice::AudioThreadCallback(
audio_parameters_, handle, length, total_segments, callback_));
audio_thread_.Start(
audio_callback_.get(), socket_handle, "AudioInputDevice", false);
state_ = RECORDING;
ipc_->RecordStream();
}
void AudioInputDevice::OnVolume(double volume) {
NOTIMPLEMENTED();
}
void AudioInputDevice::OnStateChanged(
AudioInputIPCDelegate::State state) {
DCHECK(task_runner()->BelongsToCurrentThread());
if (state_ < CREATING_STREAM)
return;
switch (state) {
case AudioInputIPCDelegate::kStopped:
ShutDownOnIOThread();
break;
case AudioInputIPCDelegate::kRecording:
NOTIMPLEMENTED();
break;
case AudioInputIPCDelegate::kError:
DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)";
if (!audio_thread_.IsStopped())
callback_->OnCaptureError();
break;
default:
NOTREACHED();
break;
}
}
void AudioInputDevice::OnIPCClosed() {
DCHECK(task_runner()->BelongsToCurrentThread());
state_ = IPC_CLOSED;
ipc_.reset();
}
AudioInputDevice::~AudioInputDevice() {
DCHECK(audio_thread_.IsStopped());
}
void AudioInputDevice::StartUpOnIOThread() {
DCHECK(task_runner()->BelongsToCurrentThread());
if (state_ != IDLE)
return;
if (session_id_ <= 0) {
DLOG(WARNING) << "Invalid session id for the input stream " << session_id_;
return;
}
state_ = CREATING_STREAM;
ipc_->CreateStream(this, session_id_, audio_parameters_,
agc_is_enabled_, kRequestedSharedMemoryCount);
}
void AudioInputDevice::ShutDownOnIOThread() {
DCHECK(task_runner()->BelongsToCurrentThread());
if (state_ >= CREATING_STREAM) {
ipc_->CloseStream();
state_ = IDLE;
agc_is_enabled_ = false;
}
base::AutoLock auto_lock_(audio_thread_lock_);
base::ThreadRestrictions::ScopedAllowIO allow_io;
audio_thread_.Stop(NULL);
audio_callback_.reset();
stopping_hack_ = false;
}
void AudioInputDevice::SetVolumeOnIOThread(double volume) {
DCHECK(task_runner()->BelongsToCurrentThread());
if (state_ >= CREATING_STREAM)
ipc_->SetVolume(volume);
}
void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) {
DCHECK(task_runner()->BelongsToCurrentThread());
if (state_ >= CREATING_STREAM) {
DLOG(WARNING) << "The AGC state can not be modified after starting.";
return;
}
agc_is_enabled_ = enabled;
}
void AudioInputDevice::WillDestroyCurrentMessageLoop() {
LOG(ERROR) << "IO loop going away before the input device has been stopped";
ShutDownOnIOThread();
}
AudioInputDevice::AudioThreadCallback::AudioThreadCallback(
const AudioParameters& audio_parameters,
base::SharedMemoryHandle memory,
int memory_length,
int total_segments,
CaptureCallback* capture_callback)
: AudioDeviceThread::Callback(audio_parameters, memory, memory_length,
total_segments),
current_segment_id_(0),
capture_callback_(capture_callback) {
audio_bus_ = AudioBus::Create(audio_parameters_);
}
AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() {
}
void AudioInputDevice::AudioThreadCallback::MapSharedMemory() {
shared_memory_.Map(memory_length_);
}
void AudioInputDevice::AudioThreadCallback::Process(int pending_data) {
uint8* ptr = static_cast<uint8*>(shared_memory_.memory());
ptr += current_segment_id_ * segment_length_;
AudioInputBuffer* buffer = reinterpret_cast<AudioInputBuffer*>(ptr);
DCHECK_GE(buffer->params.size,
segment_length_ - sizeof(AudioInputBufferParameters));
double volume = buffer->params.volume;
bool key_pressed = buffer->params.key_pressed;
int audio_delay_milliseconds = pending_data / bytes_per_ms_;
int16* memory = reinterpret_cast<int16*>(&buffer->audio[0]);
const int bytes_per_sample = sizeof(memory[0]);
if (++current_segment_id_ >= total_segments_)
current_segment_id_ = 0;
audio_bus_->FromInterleaved(memory, audio_bus_->frames(), bytes_per_sample);
capture_callback_->Capture(
audio_bus_.get(), audio_delay_milliseconds, volume, key_pressed);
}
}