0

webcodecs: Binding for Mojo Audio Encoder

This CL allows to exercise MojoAudioEncoder from WebCodecs.
Since platform audio encoder is not ready yet, we just
use the same AudioOpusEncoder on the GPU side, in order
to see that all the mojo wires are properly connected.

It will be replaces by the AAC encoder when it's ready.

Bug: 1259883
Change-Id: I55e41fba94e225bc5a6d8154255676ac4703a910
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3308655
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Reviewed-by: Alex Gough <ajgo@chromium.org>
Reviewed-by: Chrome Cunningham <chcunningham@chromium.org>
Commit-Queue: Eugene Zemtsov <eugene@chromium.org>
Cr-Commit-Position: refs/heads/main@{#956402}
This commit is contained in:
Eugene Zemtsov
2022-01-07 06:04:45 +00:00
committed by Chromium LUCI CQ
parent 3aef64d992
commit e65e6ba5ee
24 changed files with 195 additions and 10 deletions

@ -234,6 +234,7 @@ RecordingEncoderMuxer::RecordingEncoderMuxer(
if (audio_input_params) {
media::AudioEncoder::Options audio_encoder_options;
audio_encoder_options.codec = media::AudioCodec::kOpus;
audio_encoder_options.channels = audio_input_params->channels();
audio_encoder_options.sample_rate = audio_input_params->sample_rate();
InitializeAudioEncoder(audio_encoder_options);

@ -49,6 +49,15 @@ void FramelessMediaInterfaceProxy::CreateVideoDecoder(
factory->CreateVideoDecoder(std::move(receiver));
}
void FramelessMediaInterfaceProxy::CreateAudioEncoder(
mojo::PendingReceiver<media::mojom::AudioEncoder> receiver) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
InterfaceFactory* factory = GetMediaInterfaceFactory();
if (factory)
factory->CreateAudioEncoder(std::move(receiver));
}
void FramelessMediaInterfaceProxy::CreateDefaultRenderer(
const std::string& audio_device_id,
mojo::PendingReceiver<media::mojom::Renderer> receiver) {}

@ -45,6 +45,8 @@ class FramelessMediaInterfaceProxy final
mojo::PendingReceiver<media::mojom::AudioDecoder> receiver) final;
void CreateVideoDecoder(
mojo::PendingReceiver<media::mojom::VideoDecoder> receiver) final;
void CreateAudioEncoder(
mojo::PendingReceiver<media::mojom::AudioEncoder> receiver) final;
void CreateDefaultRenderer(
const std::string& audio_device_id,
mojo::PendingReceiver<media::mojom::Renderer> receiver) final;

@ -261,6 +261,14 @@ void MediaInterfaceProxy::CreateVideoDecoder(
factory->CreateVideoDecoder(std::move(receiver));
}
void MediaInterfaceProxy::CreateAudioEncoder(
mojo::PendingReceiver<media::mojom::AudioEncoder> receiver) {
DCHECK(thread_checker_.CalledOnValidThread());
InterfaceFactory* factory = media_interface_factory_ptr_->Get();
if (factory)
factory->CreateAudioEncoder(std::move(receiver));
}
void MediaInterfaceProxy::CreateDefaultRenderer(
const std::string& audio_device_id,
mojo::PendingReceiver<media::mojom::Renderer> receiver) {

@ -57,6 +57,8 @@ class MediaInterfaceProxy final : public DocumentUserData<MediaInterfaceProxy>,
mojo::PendingReceiver<media::mojom::AudioDecoder> receiver) final;
void CreateVideoDecoder(
mojo::PendingReceiver<media::mojom::VideoDecoder> receiver) final;
void CreateAudioEncoder(
mojo::PendingReceiver<media::mojom::AudioEncoder> receiver) final;
void CreateDefaultRenderer(
const std::string& audio_device_id,
mojo::PendingReceiver<media::mojom::Renderer> receiver) final;

@ -61,6 +61,19 @@ void MediaInterfaceFactory::CreateVideoDecoder(
GetMediaInterfaceFactory()->CreateVideoDecoder(std::move(receiver));
}
void MediaInterfaceFactory::CreateAudioEncoder(
mojo::PendingReceiver<media::mojom::AudioEncoder> receiver) {
if (!task_runner_->BelongsToCurrentThread()) {
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&MediaInterfaceFactory::CreateAudioEncoder,
weak_this_, std::move(receiver)));
return;
}
DVLOG(1) << __func__;
GetMediaInterfaceFactory()->CreateAudioEncoder(std::move(receiver));
}
void MediaInterfaceFactory::CreateDefaultRenderer(
const std::string& audio_device_id,
mojo::PendingReceiver<media::mojom::Renderer> receiver) {

@ -49,6 +49,8 @@ class MediaInterfaceFactory final : public media::mojom::InterfaceFactory {
mojo::PendingReceiver<media::mojom::AudioDecoder> receiver) final;
void CreateVideoDecoder(
mojo::PendingReceiver<media::mojom::VideoDecoder> receiver) final;
void CreateAudioEncoder(
mojo::PendingReceiver<media::mojom::AudioEncoder> receiver) final;
void CreateDefaultRenderer(
const std::string& audio_device_id,
mojo::PendingReceiver<media::mojom::Renderer> receiver) final;

@ -61,6 +61,7 @@ class AudioEncodersTest : public ::testing::TestWithParam<TestAudioParams> {
: audio_source_(GetParam().channels,
/*freq=*/440,
GetParam().sample_rate) {
options_.codec = AudioCodec::kOpus;
options_.sample_rate = GetParam().sample_rate;
options_.channels = GetParam().channels;
}

@ -8,6 +8,10 @@
namespace features {
// Allows usage of OS-level (platform) audio encoders.
const base::Feature kPlatformAudioEncoder{"PlatformAudioEncoder",
base::FEATURE_DISABLED_BY_DEFAULT};
// When the audio service in a separate process, kill it when a hang is
// detected. It will be restarted when needed.
const base::Feature kAudioServiceOutOfProcessKillAtHang{

@ -12,6 +12,7 @@
namespace features {
MEDIA_EXPORT extern const base::Feature kPlatformAudioEncoder;
MEDIA_EXPORT extern const base::Feature kAudioServiceOutOfProcessKillAtHang;
MEDIA_EXPORT extern const base::Feature kDumpOnAudioServiceHang;

@ -118,6 +118,11 @@ void AudioOpusEncoder::Initialize(const Options& options,
return;
}
if (options.codec != AudioCodec::kOpus) {
std::move(done_cb).Run(EncoderStatus::Codes::kEncoderInitializationError);
return;
}
options_ = options;
input_params_ = CreateInputParams(options);
if (!input_params_.IsValid()) {

@ -221,6 +221,10 @@ if (enable_library_cdms) {
_default_mojo_media_services += [ "cdm" ]
}
if (is_win) {
_default_mojo_media_services += [ "audio_encoder" ]
}
declare_args() {
# A list of mojo media services that should be used in the media pipeline.
# Valid entries in the list are:

@ -13,6 +13,7 @@ buildflag_header("buildflags") {
enable_mojo_renderer = false
enable_mojo_cdm = false
enable_mojo_audio_decoder = false
enable_mojo_audio_encoder = false
enable_mojo_video_decoder = false
enable_mojo_media_in_browser_process = false
enable_mojo_media_in_gpu_process = false
@ -24,6 +25,8 @@ buildflag_header("buildflags") {
enable_mojo_cdm = true
} else if (service == "audio_decoder") {
enable_mojo_audio_decoder = true
} else if (service == "audio_encoder") {
enable_mojo_audio_encoder = true
} else if (service == "video_decoder") {
enable_mojo_video_decoder = true
} else {
@ -44,6 +47,7 @@ buildflag_header("buildflags") {
"ENABLE_MOJO_RENDERER=$enable_mojo_renderer",
"ENABLE_MOJO_CDM=$enable_mojo_cdm",
"ENABLE_MOJO_AUDIO_DECODER=$enable_mojo_audio_decoder",
"ENABLE_MOJO_AUDIO_ENCODER=$enable_mojo_audio_encoder",
"ENABLE_MOJO_VIDEO_DECODER=$enable_mojo_video_decoder",
"ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS=$enable_mojo_media_in_browser_process",
"ENABLE_MOJO_MEDIA_IN_GPU_PROCESS=$enable_mojo_media_in_gpu_process",

@ -5,6 +5,7 @@
module media.mojom;
import "media/mojo/mojom/audio_decoder.mojom";
import "media/mojo/mojom/audio_encoder.mojom";
import "media/mojo/mojom/decryptor.mojom";
import "media/mojo/mojom/content_decryption_module.mojom";
import "media/mojo/mojom/media_log.mojom";
@ -20,6 +21,9 @@ interface InterfaceFactory {
CreateAudioDecoder(pending_receiver<AudioDecoder> audio_decoder);
CreateVideoDecoder(pending_receiver<VideoDecoder> video_decoder);
// Creates an AudioEncoder bound to a given receiver.
CreateAudioEncoder(pending_receiver<AudioEncoder> audio_encoder);
// Creates a regular media::Renderer (DefaultRendererFactory).
// TODO(guohuideng): remove |audio_device_id|, it's not used.
CreateDefaultRenderer(string audio_device_id,

@ -9,12 +9,16 @@
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/task/thread_pool.h"
#include "build/chromeos_buildflags.h"
#include "gpu/ipc/service/gpu_channel.h"
#include "media/audio/audio_features.h"
#include "media/audio/audio_opus_encoder.h"
#include "media/base/audio_decoder.h"
#include "media/base/cdm_factory.h"
#include "media/base/media_switches.h"
#include "media/base/media_util.h"
#include "media/base/offloading_audio_encoder.h"
#include "media/base/video_decoder.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/gpu/gpu_video_decode_accelerator_factory.h"
@ -111,6 +115,20 @@ std::unique_ptr<AudioDecoder> GpuMojoMediaClient::CreateAudioDecoder(
return CreatePlatformAudioDecoder(task_runner);
}
std::unique_ptr<AudioEncoder> GpuMojoMediaClient::CreateAudioEncoder(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
if (!base::FeatureList::IsEnabled(features::kPlatformAudioEncoder))
return nullptr;
// TODO(crbug.com/1259883) Right now Opus encoder is all we have, later on
// we'll create a real platform encoder here.
auto opus_encoder = std::make_unique<AudioOpusEncoder>();
auto encoding_runner = base::ThreadPool::CreateSequencedTaskRunner(
{base::TaskPriority::USER_BLOCKING});
return std::make_unique<OffloadingAudioEncoder>(std::move(opus_encoder),
std::move(encoding_runner),
std::move(task_runner));
}
VideoDecoderType GpuMojoMediaClient::GetDecoderImplementationType() {
return GetPlatformDecoderImplementationType(gpu_workarounds_,
gpu_preferences_, gpu_info_);

@ -133,6 +133,9 @@ class GpuMojoMediaClient final : public MojoMediaClient {
VideoDecoderType GetDecoderImplementationType() final;
std::unique_ptr<AudioDecoder> CreateAudioDecoder(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) final;
std::unique_ptr<AudioEncoder> CreateAudioEncoder(
scoped_refptr<base::SequencedTaskRunner> task_runner) final;
std::unique_ptr<VideoDecoder> CreateVideoDecoder(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
MediaLog* media_log,

@ -19,6 +19,10 @@
#include "media/mojo/services/mojo_audio_decoder_service.h"
#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
#if BUILDFLAG(ENABLE_MOJO_AUDIO_ENCODER)
#include "media/mojo/services/mojo_audio_encoder_service.h"
#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_ENCODER)
#if BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
#include "media/mojo/services/mojo_video_decoder_service.h"
#endif // BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
@ -85,6 +89,23 @@ void InterfaceFactoryImpl::CreateVideoDecoder(
#endif // BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
}
void InterfaceFactoryImpl::CreateAudioEncoder(
mojo::PendingReceiver<mojom::AudioEncoder> receiver) {
#if BUILDFLAG(ENABLE_MOJO_AUDIO_ENCODER)
auto runner = base::ThreadTaskRunnerHandle::Get();
auto underlying_encoder = mojo_media_client_->CreateAudioEncoder(runner);
if (!underlying_encoder) {
DLOG(ERROR) << "AudioEncoder creation failed.";
return;
}
audio_encoder_receivers_.Add(
std::make_unique<MojoAudioEncoderService>(std::move(underlying_encoder)),
std::move(receiver));
#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_ENCODER)
}
void InterfaceFactoryImpl::CreateDefaultRenderer(
const std::string& audio_device_id,
mojo::PendingReceiver<mojom::Renderer> receiver) {
@ -204,6 +225,11 @@ bool InterfaceFactoryImpl::IsEmpty() {
return false;
#endif // BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
#if BUILDFLAG(ENABLE_MOJO_AUDIO_ENCODER)
if (!audio_encoder_receivers_.empty())
return false;
#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_ENCODER)
#if BUILDFLAG(ENABLE_MOJO_RENDERER)
if (!renderer_receivers_.empty())
return false;
@ -235,6 +261,10 @@ void InterfaceFactoryImpl::SetReceiverDisconnectHandler() {
video_decoder_receivers_.set_disconnect_handler(disconnect_cb);
#endif // BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
#if BUILDFLAG(ENABLE_MOJO_AUDIO_ENCODER)
audio_encoder_receivers_.set_disconnect_handler(disconnect_cb);
#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_ENCODER)
#if BUILDFLAG(ENABLE_MOJO_RENDERER)
renderer_receivers_.set_disconnect_handler(disconnect_cb);
#endif // BUILDFLAG(ENABLE_MOJO_RENDERER)

@ -15,6 +15,7 @@
#include "media/media_buildflags.h"
#include "media/mojo/buildflags.h"
#include "media/mojo/mojom/audio_decoder.mojom.h"
#include "media/mojo/mojom/audio_encoder.mojom.h"
#include "media/mojo/mojom/content_decryption_module.mojom.h"
#include "media/mojo/mojom/decryptor.mojom.h"
#include "media/mojo/mojom/frame_interface_factory.mojom.h"
@ -53,6 +54,10 @@ class InterfaceFactoryImpl final
mojo::PendingReceiver<mojom::AudioDecoder> receiver) final;
void CreateVideoDecoder(
mojo::PendingReceiver<mojom::VideoDecoder> receiver) final;
void CreateAudioEncoder(
mojo::PendingReceiver<mojom::AudioEncoder> receiver) final;
void CreateDefaultRenderer(
const std::string& audio_device_id,
mojo::PendingReceiver<mojom::Renderer> receiver) final;
@ -124,6 +129,10 @@ class InterfaceFactoryImpl final
mojo::UniqueReceiverSet<mojom::VideoDecoder> video_decoder_receivers_;
#endif // BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
#if BUILDFLAG(ENABLE_MOJO_AUDIO_ENCODER)
mojo::UniqueReceiverSet<mojom::AudioEncoder> audio_encoder_receivers_;
#endif // BUILDFLAG(ENABLE_MOJO_VIDEO_ENCODER)
#if BUILDFLAG(ENABLE_MOJO_RENDERER) || BUILDFLAG(ENABLE_CAST_RENDERER) || \
defined(OS_WIN)
// TODO(xhwang): Use MojoMediaLog for Renderer.

@ -6,6 +6,7 @@
#include "base/task/single_thread_task_runner.h"
#include "media/base/audio_decoder.h"
#include "media/base/audio_encoder.h"
#include "media/base/cdm_factory.h"
#include "media/base/media_log.h"
#include "media/base/renderer.h"
@ -24,6 +25,11 @@ std::unique_ptr<AudioDecoder> MojoMediaClient::CreateAudioDecoder(
return nullptr;
}
std::unique_ptr<AudioEncoder> MojoMediaClient::CreateAudioEncoder(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
return nullptr;
}
SupportedVideoDecoderConfigs
MojoMediaClient::GetSupportedVideoDecoderConfigs() {
return {};

@ -32,6 +32,7 @@ class ColorSpace;
namespace media {
class AudioDecoder;
class AudioEncoder;
class CdmFactory;
class MediaLog;
class Renderer;
@ -54,6 +55,9 @@ class MEDIA_MOJO_EXPORT MojoMediaClient {
virtual std::unique_ptr<AudioDecoder> CreateAudioDecoder(
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
virtual std::unique_ptr<AudioEncoder> CreateAudioEncoder(
scoped_refptr<base::SequencedTaskRunner> task_runner);
virtual std::vector<SupportedVideoDecoderConfig>
GetSupportedVideoDecoderConfigs();

@ -112,6 +112,8 @@ class FakeInterfaceFactory : public media::mojom::InterfaceFactory {
&cdm_service_context_, std::make_unique<FakeAudioDecoder>()),
std::move(receiver));
}
void CreateAudioEncoder(
mojo::PendingReceiver<media::mojom::AudioEncoder> receiver) override {}
// Stub out other mojom::InterfaceFactory interfaces.
void CreateVideoDecoder(

@ -7,16 +7,23 @@
#include <cinttypes>
#include <limits>
#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_conversions.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
#include "media/audio/audio_features.h"
#include "media/audio/audio_opus_encoder.h"
#include "media/base/audio_parameters.h"
#include "media/base/limits.h"
#include "media/base/mime_util.h"
#include "media/base/offloading_audio_encoder.h"
#include "media/mojo/clients/mojo_audio_encoder.h"
#include "media/mojo/mojom/audio_encoder.mojom-blink.h"
#include "media/mojo/mojom/interface_factory.mojom.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_init.h"
@ -45,10 +52,10 @@ AudioEncoderTraits::ParsedConfig* ParseConfigStatic(
}
auto* result = MakeGarbageCollected<AudioEncoderTraits::ParsedConfig>();
result->codec = media::AudioCodec::kUnknown;
result->options.codec = media::AudioCodec::kUnknown;
bool is_codec_ambiguous = true;
bool parse_succeeded = ParseAudioCodecString(
"", config->codec().Utf8(), &is_codec_ambiguous, &result->codec);
"", config->codec().Utf8(), &is_codec_ambiguous, &result->options.codec);
if (!parse_succeeded || is_codec_ambiguous) {
exception_state.ThrowTypeError("Unknown codec.");
@ -90,7 +97,7 @@ AudioEncoderTraits::ParsedConfig* ParseConfigStatic(
bool VerifyCodecSupportStatic(AudioEncoderTraits::ParsedConfig* config,
ExceptionState* exception_state) {
switch (config->codec) {
switch (config->options.codec) {
case media::AudioCodec::kOpus: {
if (config->options.channels > 2) {
// Our Opus implementation only supports up to 2 channels
@ -137,6 +144,34 @@ AudioEncoderConfig* CopyConfig(const AudioEncoderConfig& config) {
return result;
}
std::unique_ptr<media::AudioEncoder> CreateSoftwareAudioEncoder(
media::AudioCodec codec) {
if (codec != media::AudioCodec::kOpus)
return nullptr;
auto software_encoder = std::make_unique<media::AudioOpusEncoder>();
return std::make_unique<media::OffloadingAudioEncoder>(
std::move(software_encoder));
}
std::unique_ptr<media::AudioEncoder> CreatePlatformAudioEncoder(
media::AudioCodec codec) {
if (!base::FeatureList::IsEnabled(features::kPlatformAudioEncoder))
return nullptr;
if (codec != media::AudioCodec::kOpus)
return nullptr;
mojo::PendingRemote<media::mojom::InterfaceFactory> pending_interface_factory;
mojo::Remote<media::mojom::InterfaceFactory> interface_factory;
Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
pending_interface_factory.InitWithNewPipeAndPassReceiver());
interface_factory.Bind(std::move(pending_interface_factory));
mojo::PendingRemote<media::mojom::AudioEncoder> encoder_remote;
interface_factory->CreateAudioEncoder(
encoder_remote.InitWithNewPipeAndPassReceiver());
return std::make_unique<media::MojoAudioEncoder>(std::move(encoder_remote));
}
} // namespace
// static
@ -162,18 +197,33 @@ AudioEncoder::AudioEncoder(ScriptState* script_state,
AudioEncoder::~AudioEncoder() = default;
std::unique_ptr<media::AudioEncoder> AudioEncoder::CreateMediaAudioEncoder(
const ParsedConfig& config) {
if (auto result = CreatePlatformAudioEncoder(config.options.codec))
return result;
return CreateSoftwareAudioEncoder(config.options.codec);
}
void AudioEncoder::ProcessConfigure(Request* request) {
DCHECK_NE(state_.AsEnum(), V8CodecState::Enum::kClosed);
DCHECK_EQ(request->type, Request::Type::kConfigure);
DCHECK(active_config_);
DCHECK_EQ(active_config_->codec, media::AudioCodec::kOpus);
DCHECK_EQ(active_config_->options.codec, media::AudioCodec::kOpus);
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
request->StartTracing();
auto software_encoder = std::make_unique<media::AudioOpusEncoder>();
media_encoder_ = std::make_unique<media::OffloadingAudioEncoder>(
std::move(software_encoder));
media_encoder_ = CreateMediaAudioEncoder(*active_config_);
if (!media_encoder_) {
HandleError(logger_->MakeException(
"Encoder creation error.",
media::EncoderStatus(
media::EncoderStatus::Codes::kEncoderInitializationError,
"Unable to create encoder (most likely unsupported "
"codec/acceleration requirement combination)")));
request->EndTracing();
return;
}
auto output_cb = ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
&AudioEncoder::CallOutputCallback, WrapCrossThreadWeakPersistent(this),
@ -207,7 +257,7 @@ void AudioEncoder::ProcessConfigure(Request* request) {
active_config_->options, std::move(output_cb),
ConvertToBaseOnceCallback(CrossThreadBindOnce(
done_callback, WrapCrossThreadWeakPersistent(this),
active_config_->codec, WrapCrossThreadPersistent(request))));
active_config_->options.codec, WrapCrossThreadPersistent(request))));
}
void AudioEncoder::ProcessEncode(Request* request) {
@ -283,7 +333,7 @@ AudioEncoder::ParsedConfig* AudioEncoder::ParseConfig(
bool AudioEncoder::CanReconfigure(ParsedConfig& original_config,
ParsedConfig& new_config) {
return original_config.codec == new_config.codec &&
return original_config.options.codec == new_config.options.codec &&
original_config.options.channels == new_config.options.channels &&
original_config.options.bitrate == new_config.options.bitrate &&
original_config.options.sample_rate == new_config.options.sample_rate;

@ -26,7 +26,6 @@ class AudioEncoderInit;
class MODULES_EXPORT AudioEncoderTraits {
public:
struct ParsedConfig final : public GarbageCollected<ParsedConfig> {
media::AudioCodec codec = media::AudioCodec::kUnknown;
media::AudioEncoder::Options options;
String codec_string;
@ -85,6 +84,8 @@ class MODULES_EXPORT AudioEncoder final
bool CanReconfigure(ParsedConfig& original_config,
ParsedConfig& new_config) override;
std::unique_ptr<media::AudioEncoder> CreateMediaAudioEncoder(
const ParsedConfig& config);
void CallOutputCallback(
ParsedConfig* active_config,
uint32_t reset_count,

@ -122,6 +122,8 @@ class FakeInterfaceFactory : public media::mojom::InterfaceFactory {
// Stub out other mojom::InterfaceFactory interfaces.
void CreateAudioDecoder(
mojo::PendingReceiver<media::mojom::AudioDecoder> receiver) override {}
void CreateAudioEncoder(
mojo::PendingReceiver<media::mojom::AudioEncoder> receiver) override {}
void CreateDefaultRenderer(
const std::string& audio_device_id,
mojo::PendingReceiver<media::mojom::Renderer> receiver) override {}