#include "media/audio/android/aaudio_input.h"
#include "base/task/bind_post_task.h"
#include "media/audio/android/audio_device.h"
#include "media/audio/android/audio_manager_android.h"
#include "media/base/amplitude_peak_detector.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_sample_types.h"
namespace media {
AAudioInputStream::AAudioInputStream(AudioManagerAndroid* manager,
const AudioParameters& params,
android::AudioDevice device)
: audio_manager_(manager),
params_(params),
device_(std::move(device)),
peak_detector_(base::BindRepeating(&AudioManager::TraceAmplitudePeak,
base::Unretained(audio_manager_),
true)) {
CHECK(audio_manager_);
handle_device_change_on_main_sequence_ =
base::BindPostTaskToCurrentDefault(base::BindRepeating(
&AAudioInputStream::HandleDeviceChange, weak_factory_.GetWeakPtr()));
}
AAudioInputStream::~AAudioInputStream() = default;
void AAudioInputStream::CreateStreamWrapper() {
CHECK(!stream_wrapper_);
stream_wrapper_ = std::make_unique<AAudioStreamWrapper>(
this, AAudioStreamWrapper::StreamType::kInput, params_, device_,
AAUDIO_USAGE_VOICE_COMMUNICATION);
}
AudioInputStream::OpenOutcome AAudioInputStream::Open() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CreateStreamWrapper();
if (!stream_wrapper_->Open()) {
return AudioInputStream::OpenOutcome::kFailed;
}
audio_bus_ = AudioBus::Create(params_);
return AudioInputStream::OpenOutcome::kSuccess;
}
void AAudioInputStream::Start(AudioInputCallback* callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(stream_wrapper_);
{
base::AutoLock al(lock_);
if (error_during_device_change_) {
callback->OnError();
return;
}
CHECK(!callback_);
callback_ = callback;
}
if (stream_wrapper_->Start()) {
audio_manager_->OnStartAAudioInputStream(this);
return;
}
{
base::AutoLock al(lock_);
callback_->OnError();
callback_ = nullptr;
}
}
void AAudioInputStream::Stop() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(stream_wrapper_);
AudioInputCallback* temp_error_callback;
{
base::AutoLock al(lock_);
if (!callback_) {
return;
}
temp_error_callback = callback_;
callback_ = nullptr;
}
audio_manager_->OnStopAAudioInputStream(this);
if (!stream_wrapper_->Stop()) {
temp_error_callback->OnError();
}
}
void AAudioInputStream::Close() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (stream_wrapper_) {
Stop();
stream_wrapper_->Close();
}
audio_manager_->ReleaseInputStream(this);
}
bool AAudioInputStream::OnAudioDataRequested(void* audio_data,
int32_t num_frames) {
CHECK_EQ(num_frames, audio_bus_->frames());
base::AutoLock al(lock_);
if (!callback_) {
return false;
}
audio_bus_->FromInterleaved<Float32SampleTypeTraits>(
reinterpret_cast<float*>(audio_data), num_frames);
peak_detector_.FindPeak(audio_bus_.get());
const base::TimeTicks capture_time = stream_wrapper_->GetCaptureTimestamp();
callback_->OnData(audio_bus_.get(), capture_time, 0.0, {});
return true;
}
void AAudioInputStream::OnError() {
base::AutoLock al(lock_);
if (callback_) {
callback_->OnError();
}
}
void AAudioInputStream::OnDeviceChange() {
handle_device_change_on_main_sequence_.Run();
}
void AAudioInputStream::HandleDeviceChange() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(stream_wrapper_);
stream_wrapper_->Close();
stream_wrapper_.reset();
CreateStreamWrapper();
bool open_success = stream_wrapper_->Open();
base::AutoLock al(lock_);
if (!open_success) {
if (callback_) {
callback_->OnError();
} else {
error_during_device_change_ = true;
}
return;
}
if (!callback_) {
return;
}
if (!stream_wrapper_->Start()) {
callback_->OnError();
}
}
std::optional<android::AudioDeviceId> AAudioInputStream::GetActualDeviceId() {
if (!stream_wrapper_) {
return std::nullopt;
}
return stream_wrapper_->GetActualDeviceId();
}
double AAudioInputStream::GetMaxVolume() {
return 0.0;
}
void AAudioInputStream::SetVolume(double volume) {}
double AAudioInputStream::GetVolume() {
return 0.0;
}
bool AAudioInputStream::SetAutomaticGainControl(bool enabled) {
return false;
}
bool AAudioInputStream::GetAutomaticGainControl() {
return false;
}
bool AAudioInputStream::IsMuted() {
return false;
}
void AAudioInputStream::SetOutputDeviceForAec(
const std::string& output_device_id) {
}
}