| Index: content/renderer/pepper/pepper_audio_encoder_host.cc
|
| diff --git a/content/renderer/pepper/pepper_audio_encoder_host.cc b/content/renderer/pepper/pepper_audio_encoder_host.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..89d770694bc3939b383322c5b212aa39b8241790
|
| --- /dev/null
|
| +++ b/content/renderer/pepper/pepper_audio_encoder_host.cc
|
| @@ -0,0 +1,402 @@
|
| +// Copyright 2015 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 "base/bind.h"
|
| +#include "base/memory/shared_memory.h"
|
| +#include "base/numerics/safe_math.h"
|
| +#include "content/public/renderer/renderer_ppapi_host.h"
|
| +#include "content/renderer/pepper/audio_encoder_shim.h"
|
| +#include "content/renderer/pepper/host_globals.h"
|
| +#include "content/renderer/pepper/pepper_audio_encoder_host.h"
|
| +#include "content/renderer/render_thread_impl.h"
|
| +#include "media/base/bind_to_current_loop.h"
|
| +#include "ppapi/c/pp_codecs.h"
|
| +#include "ppapi/c/pp_errors.h"
|
| +#include "ppapi/host/dispatch_host_message.h"
|
| +#include "ppapi/host/ppapi_host.h"
|
| +#include "ppapi/proxy/ppapi_messages.h"
|
| +#include "ppapi/shared_impl/media_stream_buffer.h"
|
| +
|
| +using ppapi::proxy::SerializedHandle;
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +// Number of input audio buffers (150ms at 10ms per frame).
|
| +const uint32_t kDefaultNumberOfAudioBuffers = 15;
|
| +
|
| +// Number of bitstream buffers.
|
| +const uint32_t kDefaultNumberOfBitstreamBuffers = 8;
|
| +
|
| +// Default bitstream buffers size.
|
| +// TODO(llandwerlin): Would having this a multiple of the audio frame
|
| +// size would make more sense?
|
| +const size_t kDefaultBitstreamBufferSize = 100000;
|
| +
|
| +bool PP_HardwareAccelerationCompatible(bool accelerated,
|
| + PP_HardwareAcceleration requested) {
|
| + switch (requested) {
|
| + case PP_HARDWAREACCELERATION_ONLY:
|
| + return accelerated;
|
| + case PP_HARDWAREACCELERATION_NONE:
|
| + return !accelerated;
|
| + case PP_HARDWAREACCELERATION_WITHFALLBACK:
|
| + return true;
|
| + // No default case, to catch unhandled PP_HardwareAcceleration values.
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +PepperAudioEncoderHost::PepperAudioEncoderHost(RendererPpapiHost* host,
|
| + PP_Instance instance,
|
| + PP_Resource resource)
|
| + : ResourceHost(host->GetPpapiHost(), instance, resource),
|
| + renderer_ppapi_host_(host),
|
| + initialized_(false),
|
| + encoder_last_error_(PP_ERROR_FAILED),
|
| + audio_buffer_manager_(this),
|
| + bitstream_buffer_manager_(this),
|
| + weak_ptr_factory_(this) {}
|
| +
|
| +PepperAudioEncoderHost::~PepperAudioEncoderHost() {
|
| + Close();
|
| +}
|
| +
|
| +int32_t PepperAudioEncoderHost::OnResourceMessageReceived(
|
| + const IPC::Message& msg,
|
| + ppapi::host::HostMessageContext* context) {
|
| + PPAPI_BEGIN_MESSAGE_MAP(PepperAudioEncoderHost, msg)
|
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
|
| + PpapiHostMsg_AudioEncoder_GetSupportedProfiles,
|
| + OnHostMsgGetSupportedProfiles)
|
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Initialize,
|
| + OnHostMsgInitialize)
|
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
|
| + PpapiHostMsg_AudioEncoder_GetAudioBuffers, OnHostMsgGetAudioBuffers)
|
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Encode,
|
| + OnHostMsgEncode)
|
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL(
|
| + PpapiHostMsg_AudioEncoder_RecycleBitstreamBuffer,
|
| + OnHostMsgRecycleBitstreamBuffer)
|
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL(
|
| + PpapiHostMsg_AudioEncoder_RequestBitrateChange,
|
| + OnHostMsgRequestBitrateChange)
|
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioEncoder_Close,
|
| + OnHostMsgClose)
|
| + PPAPI_END_MESSAGE_MAP()
|
| + return PP_ERROR_FAILED;
|
| +}
|
| +
|
| +int32_t PepperAudioEncoderHost::OnHostMsgGetSupportedProfiles(
|
| + ppapi::host::HostMessageContext* context) {
|
| + std::vector<PP_AudioProfileDescription> profiles;
|
| + GetSupportedProfiles(&profiles);
|
| +
|
| + host()->SendReply(
|
| + context->MakeReplyMessageContext(),
|
| + PpapiPluginMsg_AudioEncoder_GetSupportedProfilesReply(profiles));
|
| +
|
| + return PP_OK_COMPLETIONPENDING;
|
| +}
|
| +
|
| +int32_t PepperAudioEncoderHost::OnHostMsgInitialize(
|
| + ppapi::host::HostMessageContext* context,
|
| + const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
|
| + if (initialized_)
|
| + return PP_ERROR_FAILED;
|
| +
|
| + if (!IsInitializationValid(parameters))
|
| + return PP_ERROR_NOTSUPPORTED;
|
| +
|
| + encode_parameters_ = parameters;
|
| +
|
| + int32_t error = PP_ERROR_FAILED;
|
| + if (parameters.acceleration == PP_HARDWAREACCELERATION_NONE ||
|
| + parameters.acceleration == PP_HARDWAREACCELERATION_WITHFALLBACK) {
|
| + encoder_.reset(new AudioEncoderShim);
|
| + if (encoder_->Initialize(parameters)) {
|
| + if (AllocateBitstreamBuffers(kDefaultBitstreamBufferSize)) {
|
| + initialized_ = true;
|
| + encoder_last_error_ = PP_OK;
|
| +
|
| + ppapi::host::ReplyMessageContext reply_context =
|
| + context->MakeReplyMessageContext();
|
| + reply_context.params.AppendHandle(SerializedHandle(
|
| + renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
|
| + bitstream_buffer_manager_.shm()->handle()),
|
| + bitstream_buffer_manager_.shm()->mapped_size()));
|
| + host()->SendReply(reply_context,
|
| + PpapiPluginMsg_AudioEncoder_InitializeReply(
|
| + encoder_->GetNumberOfSamplesPerFrame(),
|
| + bitstream_buffer_manager_.number_of_buffers(),
|
| + bitstream_buffer_manager_.buffer_size()));
|
| +
|
| + return PP_OK_COMPLETIONPENDING;
|
| + }
|
| + error = PP_ERROR_NOMEMORY;
|
| + } else
|
| + error = PP_ERROR_FAILED;
|
| + }
|
| +
|
| + encoder_ = nullptr;
|
| +
|
| + return error;
|
| +}
|
| +
|
| +int32_t PepperAudioEncoderHost::OnHostMsgGetAudioBuffers(
|
| + ppapi::host::HostMessageContext* context) {
|
| + if (encoder_last_error_)
|
| + return encoder_last_error_;
|
| +
|
| + if (!AllocateAudioBuffers(encoder_->GetNumberOfSamplesPerFrame()))
|
| + return PP_ERROR_NOMEMORY;
|
| +
|
| + ppapi::host::ReplyMessageContext reply_context =
|
| + context->MakeReplyMessageContext();
|
| + reply_context.params.AppendHandle(
|
| + SerializedHandle(renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
|
| + audio_buffer_manager_.shm()->handle()),
|
| + audio_buffer_manager_.shm()->mapped_size()));
|
| +
|
| + host()->SendReply(reply_context,
|
| + PpapiPluginMsg_AudioEncoder_GetAudioBuffersReply(
|
| + audio_buffer_manager_.number_of_buffers(),
|
| + audio_buffer_manager_.buffer_size()));
|
| +
|
| + return PP_OK_COMPLETIONPENDING;
|
| +}
|
| +
|
| +int32_t PepperAudioEncoderHost::OnHostMsgEncode(
|
| + ppapi::host::HostMessageContext* context,
|
| + uint32_t buffer_id) {
|
| + if (encoder_last_error_)
|
| + return encoder_last_error_;
|
| +
|
| + if (buffer_id >=
|
| + static_cast<uint32_t>(audio_buffer_manager_.number_of_buffers()))
|
| + return PP_ERROR_BADARGUMENT;
|
| +
|
| + audio_buffer_manager_.EnqueueBuffer(buffer_id);
|
| +
|
| + DoEncode();
|
| +
|
| + return PP_OK_COMPLETIONPENDING;
|
| +}
|
| +
|
| +int32_t PepperAudioEncoderHost::OnHostMsgRecycleBitstreamBuffer(
|
| + ppapi::host::HostMessageContext* context,
|
| + uint32_t buffer_id) {
|
| + if (encoder_last_error_)
|
| + return encoder_last_error_;
|
| +
|
| + if (buffer_id >=
|
| + static_cast<uint32_t>(bitstream_buffer_manager_.number_of_buffers()))
|
| + return PP_ERROR_BADARGUMENT;
|
| +
|
| + bitstream_buffer_manager_.EnqueueBuffer(buffer_id);
|
| +
|
| + DoEncode();
|
| +
|
| + return PP_OK;
|
| +}
|
| +
|
| +int32_t PepperAudioEncoderHost::OnHostMsgRequestBitrateChange(
|
| + ppapi::host::HostMessageContext* context,
|
| + uint32_t bitrate) {
|
| + if (encoder_last_error_)
|
| + return encoder_last_error_;
|
| +
|
| + encoder_->RequestBitrateChange(bitrate);
|
| +
|
| + return PP_OK;
|
| +}
|
| +
|
| +int32_t PepperAudioEncoderHost::OnHostMsgClose(
|
| + ppapi::host::HostMessageContext* context) {
|
| + encoder_last_error_ = PP_ERROR_FAILED;
|
| + Close();
|
| +
|
| + return PP_OK;
|
| +}
|
| +
|
| +void PepperAudioEncoderHost::GetSupportedProfiles(
|
| + std::vector<PP_AudioProfileDescription>* profiles) {
|
| + DCHECK(RenderThreadImpl::current());
|
| +
|
| + AudioEncoderShim software_encoder;
|
| + *profiles = software_encoder.GetSupportedProfiles();
|
| +}
|
| +
|
| +bool PepperAudioEncoderHost::IsInitializationValid(
|
| + const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
|
| + DCHECK(RenderThreadImpl::current());
|
| +
|
| + std::vector<PP_AudioProfileDescription> profiles;
|
| + GetSupportedProfiles(&profiles);
|
| +
|
| + for (const PP_AudioProfileDescription& profile : profiles) {
|
| + if (parameters.output_profile == profile.profile &&
|
| + parameters.input_sample_size == profile.sample_size &&
|
| + parameters.input_sample_rate == profile.sample_rate &&
|
| + parameters.channels <= profile.max_channels &&
|
| + PP_HardwareAccelerationCompatible(
|
| + profile.hardware_accelerated == PP_TRUE ? true : false,
|
| + parameters.acceleration))
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +bool PepperAudioEncoderHost::AllocateAudioBuffers(uint32_t number_of_samples) {
|
| + DCHECK(RenderThreadImpl::current());
|
| + DCHECK(initialized_);
|
| +
|
| + // Buffers have already been allocated.
|
| + if (audio_buffer_manager_.number_of_buffers() > 0)
|
| + return false;
|
| +
|
| + base::CheckedNumeric<size_t> buffer_size = number_of_samples;
|
| + buffer_size *= encode_parameters_.channels;
|
| + buffer_size *= encode_parameters_.input_sample_size;
|
| + if (!buffer_size.IsValid())
|
| + return false;
|
| +
|
| + base::CheckedNumeric<size_t> total_buffer_size = buffer_size.ValueOrDie();
|
| + total_buffer_size += sizeof(ppapi::MediaStreamBuffer::Audio);
|
| + if (!total_buffer_size.IsValid())
|
| + return false;
|
| +
|
| + base::CheckedNumeric<size_t> total_memory_size =
|
| + total_buffer_size.ValueOrDie();
|
| + total_memory_size *= kDefaultNumberOfAudioBuffers;
|
| + if (!total_memory_size.IsValid())
|
| + return false;
|
| +
|
| + if (!audio_buffer_manager_.SetBuffers(
|
| + kDefaultNumberOfAudioBuffers, total_buffer_size.ValueOrDie(),
|
| + RenderThreadImpl::current()
|
| + ->HostAllocateSharedMemoryBuffer(total_memory_size.ValueOrDie())
|
| + .Pass(),
|
| + false))
|
| + return false;
|
| +
|
| + for (int32_t i = 0; i < audio_buffer_manager_.number_of_buffers(); ++i) {
|
| + ppapi::MediaStreamBuffer::Audio* buffer =
|
| + &(audio_buffer_manager_.GetBufferPointer(i)->audio);
|
| + buffer->header.size = total_buffer_size.ValueOrDie();
|
| + buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO;
|
| + buffer->sample_rate = static_cast<PP_AudioBuffer_SampleRate>(
|
| + encode_parameters_.input_sample_rate);
|
| + buffer->number_of_channels = encode_parameters_.channels;
|
| + buffer->number_of_samples = number_of_samples;
|
| + buffer->data_size = buffer_size.ValueOrDie();
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool PepperAudioEncoderHost::AllocateBitstreamBuffers(size_t buffer_size) {
|
| + DCHECK(RenderThreadImpl::current());
|
| + // We assume RequireBitstreamBuffers is only called once.
|
| + DCHECK(!initialized_);
|
| +
|
| + // Buffers have already been allocated.
|
| + if (bitstream_buffer_manager_.number_of_buffers() > 0)
|
| + return false;
|
| +
|
| + base::CheckedNumeric<size_t> total_size = buffer_size;
|
| + total_size *= kDefaultNumberOfBitstreamBuffers;
|
| + if (!total_size.IsValid())
|
| + return false;
|
| +
|
| + if (!bitstream_buffer_manager_.SetBuffers(
|
| + kDefaultNumberOfBitstreamBuffers, buffer_size,
|
| + RenderThreadImpl::current()
|
| + ->HostAllocateSharedMemoryBuffer(total_size.ValueOrDie())
|
| + .Pass(),
|
| + true))
|
| + return false;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +AudioEncoderShim::AudioData PepperAudioEncoderHost::GetAudioData(
|
| + uint32_t* buffer_id) {
|
| + DCHECK(audio_buffer_manager_.HasAvailableBuffer());
|
| + int32_t id = audio_buffer_manager_.DequeueBuffer();
|
| + ppapi::MediaStreamBuffer* buffer = audio_buffer_manager_.GetBufferPointer(id);
|
| + *buffer_id = id;
|
| + return AudioEncoderShim::AudioData(static_cast<uint8_t*>(buffer->audio.data),
|
| + buffer->audio.data_size);
|
| +}
|
| +
|
| +AudioEncoderShim::AudioData PepperAudioEncoderHost::GetBitstreamData(
|
| + uint32_t* buffer_id) {
|
| + DCHECK(bitstream_buffer_manager_.HasAvailableBuffer());
|
| + int32_t id = bitstream_buffer_manager_.DequeueBuffer();
|
| + uint8_t* buffer = reinterpret_cast<uint8_t*>(
|
| + bitstream_buffer_manager_.GetBufferPointer(id));
|
| + *buffer_id = id;
|
| + return AudioEncoderShim::AudioData(buffer,
|
| + bitstream_buffer_manager_.buffer_size());
|
| +}
|
| +
|
| +void PepperAudioEncoderHost::DoEncode() {
|
| + if (!audio_buffer_manager_.HasAvailableBuffer() ||
|
| + !bitstream_buffer_manager_.HasAvailableBuffer())
|
| + return;
|
| +
|
| + uint32_t audio_buffer_id, bitstream_buffer_id;
|
| + AudioEncoderShim::AudioData input(GetAudioData(&audio_buffer_id));
|
| + AudioEncoderShim::AudioData output(GetBitstreamData(&bitstream_buffer_id));
|
| + encoder_->Encode(input, output,
|
| + base::Bind(&PepperAudioEncoderHost::BitstreamBufferReady,
|
| + weak_ptr_factory_.GetWeakPtr(), audio_buffer_id,
|
| + bitstream_buffer_id));
|
| +}
|
| +
|
| +void PepperAudioEncoderHost::BitstreamBufferReady(
|
| + uint32_t audio_buffer_id,
|
| + uint32_t bitstream_buffer_id,
|
| + const AudioEncoderShim::AudioData& output,
|
| + int64_t size) {
|
| + DCHECK(RenderThreadImpl::current());
|
| +
|
| + if (encoder_last_error_)
|
| + return;
|
| +
|
| + host()->SendUnsolicitedReply(
|
| + pp_resource(), PpapiPluginMsg_AudioEncoder_EncodeReply(audio_buffer_id));
|
| +
|
| + if (size < 0) {
|
| + NotifyPepperError(PP_ERROR_FAILED);
|
| + return;
|
| + }
|
| +
|
| + host()->SendUnsolicitedReply(
|
| + pp_resource(), PpapiPluginMsg_AudioEncoder_BitstreamBufferReady(
|
| + bitstream_buffer_id, static_cast<uint32_t>(size)));
|
| +}
|
| +
|
| +void PepperAudioEncoderHost::NotifyPepperError(int32_t error) {
|
| + DCHECK(RenderThreadImpl::current());
|
| +
|
| + encoder_last_error_ = error;
|
| + Close();
|
| + host()->SendUnsolicitedReply(
|
| + pp_resource(),
|
| + PpapiPluginMsg_AudioEncoder_NotifyError(encoder_last_error_));
|
| +}
|
| +
|
| +void PepperAudioEncoderHost::Close() {
|
| + DCHECK(RenderThreadImpl::current());
|
| +
|
| + encoder_ = nullptr;
|
| +}
|
| +
|
| +} // namespace content
|
|
|