| Index: content/renderer/pepper/audio_encoder_shim.cc
|
| diff --git a/content/renderer/pepper/audio_encoder_shim.cc b/content/renderer/pepper/audio_encoder_shim.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a125537693bb4dd09f9ed37bfb2441f5977449c3
|
| --- /dev/null
|
| +++ b/content/renderer/pepper/audio_encoder_shim.cc
|
| @@ -0,0 +1,214 @@
|
| +// 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/thread_task_runner_handle.h"
|
| +#include "content/renderer/pepper/audio_encoder_shim.h"
|
| +#include "content/renderer/render_thread_impl.h"
|
| +#include "ppapi/c/ppb_audio_buffer.h"
|
| +#include "ppapi/proxy/serialized_structs.h"
|
| +#include "third_party/opus/src/include/opus.h"
|
| +
|
| +namespace content {
|
| +
|
| +class AudioEncoderShim::EncoderImpl {
|
| + public:
|
| + virtual ~EncoderImpl() {}
|
| +
|
| + // Called on the media thread.
|
| + void Encode(const scoped_refptr<AudioData>& input,
|
| + const scoped_refptr<AudioData>& output,
|
| + BitstreamBufferReadyCB callback);
|
| + void Stop();
|
| +
|
| + // Called on the renderer thread.
|
| + virtual std::vector<PP_AudioProfileDescription> GetSupportedProfiles() = 0;
|
| + virtual bool Initialize(
|
| + const ppapi::proxy::PPB_AudioEncodeParameters& parameters) = 0;
|
| + virtual int32_t GetNumberOfSamplesPerFrame() = 0;
|
| + virtual void RequestBitrateChange(uint32_t bitrate) = 0;
|
| +
|
| + protected:
|
| + EncoderImpl(const base::WeakPtr<AudioEncoderShim>& shim);
|
| +
|
| + // Called on the media thread.
|
| + virtual size_t EncodeInternal(const scoped_refptr<AudioData>& input,
|
| + const scoped_refptr<AudioData>& output) = 0;
|
| +
|
| + private:
|
| + base::WeakPtr<AudioEncoderShim> shim_;
|
| + scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(EncoderImpl);
|
| +};
|
| +
|
| +AudioEncoderShim::EncoderImpl::EncoderImpl(
|
| + const base::WeakPtr<AudioEncoderShim>& shim)
|
| + : shim_(shim), renderer_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
|
| +
|
| +void AudioEncoderShim::EncoderImpl::Encode(
|
| + const scoped_refptr<AudioData>& input,
|
| + const scoped_refptr<AudioData>& output,
|
| + BitstreamBufferReadyCB callback) {
|
| + size_t size = EncodeInternal(input, output);
|
| + renderer_task_runner_->PostTask(
|
| + FROM_HERE, base::Bind(&AudioEncoderShim::OnEncodeDone, shim_, output,
|
| + size < 0 ? -1 : size, callback));
|
| +}
|
| +
|
| +void AudioEncoderShim::EncoderImpl::Stop() {}
|
| +
|
| +class AudioEncoderShim::OpusEncoderImpl : public AudioEncoderShim::EncoderImpl {
|
| + public:
|
| + OpusEncoderImpl(const base::WeakPtr<AudioEncoderShim>& shim);
|
| + ~OpusEncoderImpl() override;
|
| +
|
| + private:
|
| + // AudioEncoderShim::Impl:
|
| + std::vector<PP_AudioProfileDescription> GetSupportedProfiles() override;
|
| + bool Initialize(
|
| + const ppapi::proxy::PPB_AudioEncodeParameters& parameters) override;
|
| + int32_t GetNumberOfSamplesPerFrame() override;
|
| + size_t EncodeInternal(
|
| + const scoped_refptr<AudioEncoderShim::AudioData>& input,
|
| + const scoped_refptr<AudioEncoderShim::AudioData>& output) override;
|
| + void RequestBitrateChange(uint32_t bitrate) override;
|
| +
|
| + scoped_ptr<uint8[]> encoder_memory_;
|
| + OpusEncoder* opus_encoder_;
|
| +
|
| + ppapi::proxy::PPB_AudioEncodeParameters parameters_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(OpusEncoderImpl);
|
| +};
|
| +
|
| +AudioEncoderShim::OpusEncoderImpl::OpusEncoderImpl(
|
| + const base::WeakPtr<AudioEncoderShim>& shim)
|
| + : EncoderImpl(shim), opus_encoder_(nullptr) {}
|
| +
|
| +AudioEncoderShim::OpusEncoderImpl::~OpusEncoderImpl() {}
|
| +
|
| +std::vector<PP_AudioProfileDescription>
|
| +AudioEncoderShim::OpusEncoderImpl::GetSupportedProfiles() {
|
| + std::vector<PP_AudioProfileDescription> profiles;
|
| + static const uint32_t sampling_rates[] = {8000, 12000, 16000, 24000, 48000};
|
| +
|
| + for (uint32_t i = 0; i < arraysize(sampling_rates); ++i) {
|
| + PP_AudioProfileDescription profile;
|
| + profile.profile = PP_AUDIOPROFILE_OPUS;
|
| + profile.max_channels = 2;
|
| + profile.sample_size = PP_AUDIOBUFFER_SAMPLESIZE_16_BITS;
|
| + profile.sample_rate = sampling_rates[i];
|
| + profile.hardware_accelerated = PP_FALSE;
|
| + profiles.push_back(profile);
|
| + }
|
| + return profiles;
|
| +}
|
| +
|
| +bool AudioEncoderShim::OpusEncoderImpl::Initialize(
|
| + const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
|
| + DCHECK(!encoder_memory_);
|
| +
|
| + int32_t encoder_size = opus_encoder_get_size(parameters.channels);
|
| + if (encoder_size < 1)
|
| + return false;
|
| +
|
| + encoder_memory_.reset(new uint8[encoder_size]);
|
| + opus_encoder_ = reinterpret_cast<OpusEncoder*>(encoder_memory_.get());
|
| +
|
| + if (opus_encoder_init(opus_encoder_, parameters.input_sample_rate,
|
| + parameters.channels, OPUS_APPLICATION_AUDIO) != OPUS_OK)
|
| + return false;
|
| +
|
| + if (opus_encoder_ctl(opus_encoder_,
|
| + OPUS_SET_BITRATE(parameters.initial_bitrate <= 0
|
| + ? OPUS_AUTO
|
| + : parameters.initial_bitrate)) !=
|
| + OPUS_OK)
|
| + return false;
|
| +
|
| + parameters_ = parameters;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +int32_t AudioEncoderShim::OpusEncoderImpl::GetNumberOfSamplesPerFrame() {
|
| + // Opus supports 2.5, 5, 10, 20, 40 or 60ms audio frames. We take
|
| + // 10ms by default.
|
| + return parameters_.input_sample_rate / 100;
|
| +}
|
| +
|
| +size_t AudioEncoderShim::OpusEncoderImpl::EncodeInternal(
|
| + const scoped_refptr<AudioData>& input,
|
| + const scoped_refptr<AudioData>& output) {
|
| + return opus_encode(
|
| + opus_encoder_, reinterpret_cast<opus_int16*>(input->GetData()),
|
| + (input->GetSize() / parameters_.channels) / parameters_.input_sample_size,
|
| + output->GetData(), output->GetSize());
|
| +}
|
| +
|
| +void AudioEncoderShim::OpusEncoderImpl::RequestBitrateChange(uint32_t bitrate) {
|
| + opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(bitrate));
|
| +}
|
| +
|
| +AudioEncoderShim::AudioEncoderShim()
|
| + : media_task_runner_(RenderThreadImpl::current()
|
| + ->GetMediaThreadTaskRunner()),
|
| + weak_ptr_factory_(this) {}
|
| +
|
| +AudioEncoderShim::~AudioEncoderShim() {
|
| + if (encoder_impl_)
|
| + media_task_runner_->PostTask(
|
| + FROM_HERE, base::Bind(&AudioEncoderShim::EncoderImpl::Stop,
|
| + base::Owned(encoder_impl_.release())));
|
| +}
|
| +
|
| +std::vector<PP_AudioProfileDescription>
|
| +AudioEncoderShim::GetSupportedProfiles() {
|
| + std::vector<PP_AudioProfileDescription> profiles;
|
| + scoped_ptr<EncoderImpl> encoder(
|
| + new OpusEncoderImpl(weak_ptr_factory_.GetWeakPtr()));
|
| + std::vector<PP_AudioProfileDescription> codec_profiles =
|
| + encoder->GetSupportedProfiles();
|
| + for (const auto& desc : codec_profiles)
|
| + profiles.push_back(desc);
|
| + return profiles;
|
| +}
|
| +
|
| +bool AudioEncoderShim::Initialize(
|
| + const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
|
| + if (encoder_impl_ || parameters.output_profile != PP_AUDIOPROFILE_OPUS)
|
| + return false;
|
| +
|
| + encoder_impl_.reset(new OpusEncoderImpl(weak_ptr_factory_.GetWeakPtr()));
|
| + return encoder_impl_->Initialize(parameters);
|
| +}
|
| +
|
| +int32_t AudioEncoderShim::GetNumberOfSamplesPerFrame() {
|
| + return encoder_impl_->GetNumberOfSamplesPerFrame();
|
| +}
|
| +
|
| +void AudioEncoderShim::Encode(const scoped_refptr<AudioData>& input,
|
| + const scoped_refptr<AudioData>& output,
|
| + BitstreamBufferReadyCB callback) {
|
| + media_task_runner_->PostTask(
|
| + FROM_HERE, base::Bind(&AudioEncoderShim::EncoderImpl::Encode,
|
| + base::Unretained(encoder_impl_.get()), input,
|
| + output, callback));
|
| +}
|
| +
|
| +void AudioEncoderShim::RequestBitrateChange(uint32_t bitrate) {
|
| + media_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&AudioEncoderShim::EncoderImpl::RequestBitrateChange,
|
| + base::Unretained(encoder_impl_.get()), bitrate));
|
| +}
|
| +
|
| +void AudioEncoderShim::OnEncodeDone(const scoped_refptr<AudioData>& output,
|
| + size_t size,
|
| + BitstreamBufferReadyCB callback) {
|
| + callback.Run(output, size);
|
| +}
|
| +
|
| +} // namespace content
|
|
|