#include "content/renderer/pepper/pepper_platform_audio_input.h"
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "content/child/child_process.h"
#include "content/renderer/pepper/pepper_audio_input_host.h"
#include "content/renderer/pepper/pepper_media_device_manager.h"
#include "content/renderer/render_frame_impl.h"
#include "media/audio/audio_device_description.h"
#include "media/audio/audio_source_parameters.h"
#include "ppapi/shared_impl/ppb_audio_config_shared.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/web/modules/media/audio/audio_input_ipc_factory.h"
#include "third_party/blink/public/web/web_local_frame.h"
namespace content {
PepperPlatformAudioInput* PepperPlatformAudioInput::Create(
int render_frame_id,
const std::string& device_id,
int sample_rate,
int frames_per_buffer,
PepperAudioInputHost* client) {
scoped_refptr<PepperPlatformAudioInput> audio_input(
new PepperPlatformAudioInput());
if (audio_input->Initialize(render_frame_id,
device_id,
sample_rate,
frames_per_buffer,
client)) {
audio_input->AddRef();
return audio_input.get();
}
return nullptr;
}
void PepperPlatformAudioInput::StartCapture() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
io_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&PepperPlatformAudioInput::StartCaptureOnIOThread, this));
}
void PepperPlatformAudioInput::StopCapture() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
io_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&PepperPlatformAudioInput::StopCaptureOnIOThread, this));
}
void PepperPlatformAudioInput::ShutDown() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
if (!client_)
return;
client_ = nullptr;
io_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&PepperPlatformAudioInput::ShutDownOnIOThread, this));
}
void PepperPlatformAudioInput::OnStreamCreated(
base::ReadOnlySharedMemoryRegion shared_memory_region,
base::SyncSocket::ScopedHandle socket_handle,
bool initially_muted) {
DCHECK(shared_memory_region.IsValid());
#if BUILDFLAG(IS_WIN)
DCHECK(socket_handle.IsValid());
#else
DCHECK(socket_handle.is_valid());
#endif
DCHECK_GT(shared_memory_region.GetSize(), 0u);
if (!main_task_runner_->BelongsToCurrentThread()) {
main_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&PepperPlatformAudioInput::OnStreamCreated,
this, std::move(shared_memory_region),
std::move(socket_handle), initially_muted));
} else {
if (client_) {
client_->StreamCreated(std::move(shared_memory_region),
std::move(socket_handle));
}
}
}
void PepperPlatformAudioInput::OnError(
media::AudioCapturerSource::ErrorCode code) {}
void PepperPlatformAudioInput::OnMuted(bool is_muted) {}
void PepperPlatformAudioInput::OnIPCClosed() { ipc_.reset(); }
PepperPlatformAudioInput::~PepperPlatformAudioInput() {
DCHECK(!ipc_);
DCHECK(!client_);
DCHECK(label_.empty());
DCHECK(!pending_open_device_);
}
PepperPlatformAudioInput::PepperPlatformAudioInput()
: io_task_runner_(ChildProcess::current()->io_task_runner()) {}
bool PepperPlatformAudioInput::Initialize(
int render_frame_id,
const std::string& device_id,
int sample_rate,
int frames_per_buffer,
PepperAudioInputHost* client) {
RenderFrameImpl* const render_frame =
RenderFrameImpl::FromRoutingID(render_frame_id);
if (!render_frame || !client)
return false;
main_task_runner_ =
render_frame->GetTaskRunner(blink::TaskType::kInternalMediaRealTime);
render_frame_id_ = render_frame_id;
render_frame_token_ = render_frame->GetWebFrame()->GetLocalFrameToken();
client_ = client;
if (!GetMediaDeviceManager())
return false;
params_.Reset(media::AudioParameters::AUDIO_PCM_LINEAR,
media::ChannelLayoutConfig::Mono(), sample_rate,
frames_per_buffer);
pending_open_device_id_ = GetMediaDeviceManager()->OpenDevice(
PP_DEVICETYPE_DEV_AUDIOCAPTURE,
device_id.empty() ? media::AudioDeviceDescription::kDefaultDeviceId
: device_id,
client->pp_instance(),
base::BindOnce(&PepperPlatformAudioInput::OnDeviceOpened, this));
pending_open_device_ = true;
return true;
}
void PepperPlatformAudioInput::InitializeOnIOThread(
const base::UnguessableToken& session_id) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
if (ipc_startup_state_ != kStopped) {
ipc_ = blink::AudioInputIPCFactory::CreateAudioInputIPC(
render_frame_token_, main_task_runner_,
media::AudioSourceParameters(session_id));
}
if (!ipc_)
return;
create_stream_sent_ = true;
ipc_->CreateStream(this, params_, false, 1);
if (ipc_startup_state_ == kStarted)
ipc_->RecordStream();
}
void PepperPlatformAudioInput::StartCaptureOnIOThread() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
if (!ipc_) {
ipc_startup_state_ = kStarted;
return;
}
ipc_->RecordStream();
}
void PepperPlatformAudioInput::StopCaptureOnIOThread() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
if (!ipc_) {
ipc_startup_state_ = kStopped;
return;
}
if (ipc_ && create_stream_sent_) {
ipc_->CloseStream();
}
ipc_.reset();
}
void PepperPlatformAudioInput::ShutDownOnIOThread() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
StopCaptureOnIOThread();
main_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&PepperPlatformAudioInput::CloseDevice, this));
Release();
}
void PepperPlatformAudioInput::OnDeviceOpened(int request_id,
bool succeeded,
const std::string& label) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
pending_open_device_ = false;
pending_open_device_id_ = -1;
PepperMediaDeviceManager* const device_manager = GetMediaDeviceManager();
if (succeeded && device_manager) {
DCHECK(!label.empty());
label_ = label;
if (client_) {
base::UnguessableToken session_id =
device_manager->GetSessionID(PP_DEVICETYPE_DEV_AUDIOCAPTURE, label);
io_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&PepperPlatformAudioInput::InitializeOnIOThread, this,
session_id));
} else {
CloseDevice();
}
} else {
NotifyStreamCreationFailed();
}
}
void PepperPlatformAudioInput::CloseDevice() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
if (!label_.empty()) {
PepperMediaDeviceManager* const device_manager = GetMediaDeviceManager();
if (device_manager)
device_manager->CloseDevice(label_);
label_.clear();
}
if (pending_open_device_) {
PepperMediaDeviceManager* const device_manager = GetMediaDeviceManager();
if (device_manager)
device_manager->CancelOpenDevice(pending_open_device_id_);
pending_open_device_ = false;
pending_open_device_id_ = -1;
}
}
void PepperPlatformAudioInput::NotifyStreamCreationFailed() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
if (client_)
client_->StreamCreationFailed();
}
PepperMediaDeviceManager* PepperPlatformAudioInput::GetMediaDeviceManager() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
RenderFrameImpl* const render_frame =
RenderFrameImpl::FromRoutingID(render_frame_id_);
return render_frame
? PepperMediaDeviceManager::GetForRenderFrame(render_frame).get()
: nullptr;
}
}